Compare commits
81 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| bd8edee77f | |||
| 787619cdba | |||
| 7d70be42af | |||
| 9671a654b7 | |||
| 6963157e63 | |||
| 9452c6b08c | |||
| 035875825e | |||
| 837e06e85b | |||
| 9e3132c3fc | |||
| 843d0ed298 | |||
| f7f4c049fc | |||
| 1072540e3e | |||
| 0c8c13b8b7 | |||
| 303a109286 | |||
| f0dc38cadd | |||
| 4efa2266e6 | |||
| 1f7a1e4078 | |||
| 2ead9b1f21 | |||
| ddf5b52360 | |||
| f66468ffcd | |||
| d3405da5c4 | |||
| 020d282868 | |||
| 137821c866 | |||
| e6d2e05b6e | |||
| 7b889a10cc | |||
| 1e1c2007a3 | |||
| 660f491310 | |||
| 670660c244 | |||
| 3d960064ef | |||
| f6d2409b20 | |||
| 39bc897b93 | |||
| 5f35f2ac7d | |||
| e1eb075604 | |||
| d19d9ccd0b | |||
| b4b4ae7a78 | |||
| 149fa9d750 | |||
| 791070c158 | |||
| 3bd2114815 | |||
| 46de48593c | |||
| acd384ae2d | |||
| b77666cbba | |||
| 128ee67bba | |||
| 7417033d7f | |||
| e8a940172c | |||
| 290bdc4566 | |||
| 220aab1fd0 | |||
| 8e9f456029 | |||
| aa450b56f1 | |||
| 6d70f3c237 | |||
| 6384541345 | |||
| ffb014ca3d | |||
| 3c3f92f29b | |||
| 24255f7883 | |||
| 40fa836b81 | |||
| b71caa94ac | |||
| 39658c0c52 | |||
| 9b8522e734 | |||
| 9875bf9c7b | |||
| 4ce4cf5242 | |||
| 52110e0647 | |||
| 19ce0cdc09 | |||
| 2e58f312d5 | |||
| 7523d01e0f | |||
| 7972cb5bdc | |||
| 685d5d3ea3 | |||
| 9f7caf90e3 | |||
| f453194e32 | |||
| 440c637b1f | |||
| d95809a069 | |||
| 6aac972bda | |||
| df3fddc026 | |||
| 1ce49b60d9 | |||
| 8b5b23e6c0 | |||
| 26f329d186 | |||
| 5ace4438e2 | |||
| b8e10225f9 | |||
| 224facf3ba | |||
| 9c12d8ff22 | |||
| 3b4339c8e0 | |||
| 8e12c4cb00 | |||
| aa4fb80465 |
@@ -22,3 +22,6 @@
|
||||
[submodule "GSL"]
|
||||
path = GSL
|
||||
url = https://github.com/Microsoft/GSL.git
|
||||
[submodule "libpng"]
|
||||
path = libpng
|
||||
url = https://github.com/RPCS3/libpng
|
||||
|
||||
+6
-3
@@ -33,8 +33,10 @@ git:
|
||||
before_install:
|
||||
# shutdown services on Travis, which may have a memory impact
|
||||
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
echo "yes" | sudo apt-add-repository 'deb http://repos.codelite.org/wx3.0/ubuntu/ precise universe';
|
||||
sudo apt-get install libwxgtk3.0-dev;
|
||||
sudo apt-add-repository -y ppa:libreoffice/ppa;
|
||||
sudo apt-get update;
|
||||
sudo apt-get install libglew-dev;
|
||||
fi;
|
||||
- if [ "$TRAVIS_OS_NAME" = "linux" ] && [ "$CXX" = "g++" ]; then
|
||||
export CXX="g++-5" CC="gcc-5" CXXFLAGS="-Wno-format-security";
|
||||
@@ -51,7 +53,7 @@ before_install:
|
||||
fi;
|
||||
|
||||
before_script:
|
||||
- git submodule update --init asmjit ffmpeg rsx_program_decompiler GSL
|
||||
- git submodule update --init asmjit ffmpeg rsx_program_decompiler GSL libpng
|
||||
- mkdir build
|
||||
- cd build
|
||||
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then cmake ..; else cmake .. -DLLVM_DIR=/usr/local/opt/llvm36/lib/llvm-3.6/share/llvm/cmake; fi
|
||||
@@ -73,7 +75,7 @@ addons:
|
||||
- cmake
|
||||
- libopenal-dev
|
||||
- freeglut3-dev
|
||||
- libglew-dev
|
||||
# - libglew-dev apt version is too old
|
||||
- libc6-dev
|
||||
- llvm-3.6
|
||||
- llvm-3.6-dev
|
||||
@@ -83,6 +85,7 @@ addons:
|
||||
- clang-3.6
|
||||
- libstdc++-4.8-dev
|
||||
- lib32stdc++6
|
||||
- zlib1g-dev
|
||||
coverity_scan:
|
||||
project:
|
||||
name: $TRAVIS_REPO_SLUG
|
||||
|
||||
@@ -11,7 +11,12 @@ if(NOT CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
message( FATAL_ERROR "RPCS3 can only be compiled on 64-bit platforms." )
|
||||
endif()
|
||||
|
||||
# We use libpng's static library and don't need to build the shared library and run the tests
|
||||
set(PNG_SHARED OFF CACHE BOOL "Build shared lib." FORCE)
|
||||
set(PNG_TESTS OFF CACHE BOOL "Build tests." FORCE)
|
||||
|
||||
add_subdirectory( asmjit )
|
||||
add_subdirectory( libpng )
|
||||
# TODO: do real installation, including copying directory structure
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE "${PROJECT_BINARY_DIR}/bin")
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG "${PROJECT_BINARY_DIR}/bin")
|
||||
|
||||
+2
-2
@@ -530,7 +530,7 @@ template<typename T> class se_t<T, true>
|
||||
static_assert(!std::is_pointer<type>::value, "se_t<> error: invalid type (pointer)");
|
||||
static_assert(!std::is_reference<type>::value, "se_t<> error: invalid type (reference)");
|
||||
static_assert(!std::is_array<type>::value, "se_t<> error: invalid type (array)");
|
||||
static_assert(!std::is_enum<type>::value, "se_t<> error: invalid type (enumeration), use integral type instead");
|
||||
//static_assert(!std::is_enum<type>::value, "se_t<> error: invalid type (enumeration), use integral type instead");
|
||||
static_assert(alignof(type) == alignof(stype), "se_t<> error: unexpected alignment");
|
||||
|
||||
template<typename T2, typename = void> struct bool_converter
|
||||
@@ -642,7 +642,7 @@ template<typename T> class se_t<T, false>
|
||||
static_assert(!std::is_pointer<type>::value, "se_t<> error: invalid type (pointer)");
|
||||
static_assert(!std::is_reference<type>::value, "se_t<> error: invalid type (reference)");
|
||||
static_assert(!std::is_array<type>::value, "se_t<> error: invalid type (array)");
|
||||
static_assert(!std::is_enum<type>::value, "se_t<> error: invalid type (enumeration), use integral type instead");
|
||||
//static_assert(!std::is_enum<type>::value, "se_t<> error: invalid type (enumeration), use integral type instead");
|
||||
|
||||
public:
|
||||
se_t() = default;
|
||||
|
||||
@@ -199,6 +199,16 @@ namespace fs
|
||||
CHECK_ASSERTION(seek(0) != -1 && read(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
// Read full file to std::vector
|
||||
template<typename T>
|
||||
std::enable_if_t<std::is_pod<T>::value && !std::is_pointer<T>::value, std::vector<T>> to_vector() const
|
||||
{
|
||||
std::vector<T> result;
|
||||
result.resize(size() / sizeof(T));
|
||||
CHECK_ASSERTION(seek(0) != -1 && read(result));
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
// TODO
|
||||
|
||||
+9
-10
@@ -794,16 +794,18 @@ size_t get_x64_access_size(x64_context* context, x64_op_t op, x64_reg_t reg, siz
|
||||
return d_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback that can be customised by GSRender backends to track memory access.
|
||||
* Backends can protect memory pages and get this callback called when an access
|
||||
* violation is met.
|
||||
* Should return true if the backend handles the access violation.
|
||||
*/
|
||||
std::function<bool(u32 addr)> gfxHandler = [](u32) { return false; };
|
||||
namespace rsx
|
||||
{
|
||||
extern std::function<bool(u32 addr, bool is_writing)> g_access_violation_handler;
|
||||
}
|
||||
|
||||
bool handle_access_violation(u32 addr, bool is_writing, x64_context* context)
|
||||
{
|
||||
if (rsx::g_access_violation_handler && rsx::g_access_violation_handler(addr, is_writing))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
auto code = (const u8*)RIP(context);
|
||||
|
||||
x64_op_t op;
|
||||
@@ -811,9 +813,6 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context)
|
||||
size_t d_size;
|
||||
size_t i_size;
|
||||
|
||||
if (gfxHandler(addr))
|
||||
return true;
|
||||
|
||||
// decode single x64 instruction that causes memory access
|
||||
decode_x64_reg_op(code, op, reg, d_size, i_size);
|
||||
|
||||
|
||||
+5
-3
@@ -14,10 +14,11 @@ branches:
|
||||
|
||||
before_build:
|
||||
# until git for win 2.5 release with commit checkout
|
||||
- git submodule update --init ffmpeg asmjit minidx9 rsx_program_decompiler GSL
|
||||
- git submodule update --init ffmpeg asmjit minidx9 rsx_program_decompiler GSL libpng
|
||||
- 7z x wxWidgets.7z -aos -oC:\rpcs3\wxWidgets > null
|
||||
- if %configuration%==Release (cmake -G "Visual Studio 14 Win64")
|
||||
else (7z x llvmlibs.7z -aos -oC:\rpcs3 > null && cmake -G "Visual Studio 14 Win64" -DLLVM_DIR=C:/rpcs3/llvm_build/share/llvm/cmake)
|
||||
- 7z x zlib.7z -aos -oC:\rpcs3\ > null
|
||||
- if %configuration%==Release (cmake -G "Visual Studio 14 Win64" -DZLIB_ROOT=C:/rpcs3/zlib/)
|
||||
else (7z x llvmlibs.7z -aos -oC:\rpcs3 > null && cmake -G "Visual Studio 14 Win64" -DLLVM_DIR=C:/rpcs3/llvm_build/share/llvm/cmake -DZLIB_ROOT=C:/rpcs3/zlib/)
|
||||
|
||||
build_script:
|
||||
- cmake --build . --config Release -- /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll"
|
||||
@@ -25,6 +26,7 @@ build_script:
|
||||
install:
|
||||
- ps: Start-FileDownload 'https://402331b94f8e4b87ae2ef4677347f7956cf3861f.googledrive.com/host/0B6v_qtb9hkicfmt0NG0wTTRtUmF4X3VTQk5Oc2JidEVKVnUteDA1dXdrYlNsVW9kREpsSHc/wxWidgets.7z'
|
||||
- ps: Start-FileDownload 'https://402331b94f8e4b87ae2ef4677347f7956cf3861f.googledrive.com/host/0B6v_qtb9hkicfmt0NG0wTTRtUmF4X3VTQk5Oc2JidEVKVnUteDA1dXdrYlNsVW9kREpsSHc/llvmlibs.7z'
|
||||
- ps: Start-FileDownload 'https://402331b94f8e4b87ae2ef4677347f7956cf3861f.googledrive.com/host/0B6v_qtb9hkicfmt0NG0wTTRtUmF4X3VTQk5Oc2JidEVKVnUteDA1dXdrYlNsVW9kREpsSHc/zlib.7z'
|
||||
- set WXWIN=C:\rpcs3\wxWidgets
|
||||
- set OPENALDIR=C:\rpcs3\OpenAL
|
||||
- set PATH=C:\Program Files (x86)\MSBuild\14.0\Bin;C:\wxWidgets;%PATH%
|
||||
|
||||
Submodule
+1
Submodule libpng added at ea77a6fd49
@@ -44,50 +44,32 @@
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)bin\</OutDir>
|
||||
<IncludePath>.\;..\;..\asmjit\src\asmjit;..\wxWidgets\include\msvc;..\wxWidgets\include;.\OpenAL\include;..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\Include;$(VC_IncludePath);$(WindowsSDK_IncludePath);..\llvm\include;..\llvm_build\include;$(UniversalCRT_IncludePath);..\minidx9\Include;..\minidx12\Include;..\GSL\include</IncludePath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)bin\</OutDir>
|
||||
<IncludePath>.\;..\;..\asmjit\src\asmjit;..\wxWidgets\include\msvc;..\wxWidgets\include;.\OpenAL\include;..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\Include;$(VC_IncludePath);$(WindowsSDK_IncludePath);..\llvm\include;..\llvm_build\include;$(UniversalCRT_IncludePath);..\minidx9\Include;..\minidx12\Include;..\GSL\include</IncludePath>
|
||||
</PropertyGroup>
|
||||
<ImportGroup Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\rpcs3_default.props" />
|
||||
</ImportGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>..\;..\rpcs3;$(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<UseFullPaths>true</UseFullPaths>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalLibraryDirectories>$(VCInstallDir)UnitTest\lib;..\OpenAL\libs\Win64;..\ffmpeg\Windows\x86_64\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<AdditionalIncludeDirectories>..\;..\rpcs3;$(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<UseFullPaths>true</UseFullPaths>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalLibraryDirectories>$(VCInstallDir)UnitTest\lib;..\OpenAL\libs\Win64;..\ffmpeg\Windows\x86_64\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>$(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
|
||||
@@ -17,6 +17,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rpcs3", "rpcs3\rpcs3.vcxpro
|
||||
{97FDAB45-9C58-5BC5-A2F4-EE42739EBC63} = {97FDAB45-9C58-5BC5-A2F4-EE42739EBC63}
|
||||
{A1A8355B-0988-528E-9CC2-B971D6266669} = {A1A8355B-0988-528E-9CC2-B971D6266669}
|
||||
{09F2F96A-1CC6-5E43-AF1D-956EC2A4888D} = {09F2F96A-1CC6-5E43-AF1D-956EC2A4888D}
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E} = {D6973076-9317-4EF2-A0B8-B7A18AC0713E}
|
||||
{8B867186-A0B5-5479-B824-E176EDD27C40} = {8B867186-A0B5-5479-B824-E176EDD27C40}
|
||||
{87B42A9C-3F5C-53D7-9017-2B1CAE39457D} = {87B42A9C-3F5C-53D7-9017-2B1CAE39457D}
|
||||
{8BC303AB-25BE-4276-8E57-73F171B2D672} = {8BC303AB-25BE-4276-8E57-73F171B2D672}
|
||||
@@ -197,6 +198,17 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "XAudio", "rpcs3\XAudio.vcxp
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "OpenAL", "rpcs3\OpenAL.vcxproj", "{30A05C4D-F5FD-421C-A864-17A64BDEAA75}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "libpng", "libpng", "{A17D34F1-7E3E-4841-818D-3B7C6F5AF829}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libpng", "libpng\projects\vstudio\libpng\libpng.vcxproj", "{D6973076-9317-4EF2-A0B8-B7A18AC0713E}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{60F89955-91C6-3A36-8000-13C592FEC2DF} = {60F89955-91C6-3A36-8000-13C592FEC2DF}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "zlib", "zlib", "{F0C19EFA-EDD0-43F2-97C1-18E865E96B4E}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib", "libpng\projects\vstudio\zlib\zlib.vcxproj", "{60F89955-91C6-3A36-8000-13C592FEC2DF}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug - LLVM|x64 = Debug - LLVM|x64
|
||||
@@ -693,6 +705,34 @@ Global
|
||||
{30A05C4D-F5FD-421C-A864-17A64BDEAA75}.Release - LLVM|x64.Build.0 = Release - LLVM|x64
|
||||
{30A05C4D-F5FD-421C-A864-17A64BDEAA75}.Release|x64.ActiveCfg = Release|x64
|
||||
{30A05C4D-F5FD-421C-A864-17A64BDEAA75}.Release|x64.Build.0 = Release|x64
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Debug - LLVM|x64.ActiveCfg = Debug Library|x64
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Debug - LLVM|x64.Build.0 = Debug Library|x64
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Debug - MemLeak|x64.ActiveCfg = Debug Library|x64
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Debug - MemLeak|x64.Build.0 = Debug Library|x64
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Debug|x64.Build.0 = Debug|x64
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.DLL Debug|x64.ActiveCfg = Debug|x64
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.DLL Debug|x64.Build.0 = Debug|x64
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.DLL Release|x64.ActiveCfg = Release|x64
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.DLL Release|x64.Build.0 = Release|x64
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Release - LLVM|x64.ActiveCfg = Release Library|x64
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Release - LLVM|x64.Build.0 = Release Library|x64
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Release|x64.ActiveCfg = Release|x64
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Release|x64.Build.0 = Release|x64
|
||||
{60F89955-91C6-3A36-8000-13C592FEC2DF}.Debug - LLVM|x64.ActiveCfg = Debug Library|x64
|
||||
{60F89955-91C6-3A36-8000-13C592FEC2DF}.Debug - LLVM|x64.Build.0 = Debug Library|x64
|
||||
{60F89955-91C6-3A36-8000-13C592FEC2DF}.Debug - MemLeak|x64.ActiveCfg = Debug Library|x64
|
||||
{60F89955-91C6-3A36-8000-13C592FEC2DF}.Debug - MemLeak|x64.Build.0 = Debug Library|x64
|
||||
{60F89955-91C6-3A36-8000-13C592FEC2DF}.Debug|x64.ActiveCfg = Debug Library|x64
|
||||
{60F89955-91C6-3A36-8000-13C592FEC2DF}.Debug|x64.Build.0 = Debug Library|x64
|
||||
{60F89955-91C6-3A36-8000-13C592FEC2DF}.DLL Debug|x64.ActiveCfg = Debug Library|x64
|
||||
{60F89955-91C6-3A36-8000-13C592FEC2DF}.DLL Debug|x64.Build.0 = Debug Library|x64
|
||||
{60F89955-91C6-3A36-8000-13C592FEC2DF}.DLL Release|x64.ActiveCfg = Release Library|x64
|
||||
{60F89955-91C6-3A36-8000-13C592FEC2DF}.DLL Release|x64.Build.0 = Release Library|x64
|
||||
{60F89955-91C6-3A36-8000-13C592FEC2DF}.Release - LLVM|x64.ActiveCfg = Release Library|x64
|
||||
{60F89955-91C6-3A36-8000-13C592FEC2DF}.Release - LLVM|x64.Build.0 = Release Library|x64
|
||||
{60F89955-91C6-3A36-8000-13C592FEC2DF}.Release|x64.ActiveCfg = Release Library|x64
|
||||
{60F89955-91C6-3A36-8000-13C592FEC2DF}.Release|x64.Build.0 = Release Library|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@@ -730,5 +770,7 @@ Global
|
||||
{7D73447B-3D2D-4DFE-BF62-57E644C1D09F} = {10FBF193-D532-4CCF-B875-4C7091A7F6C2}
|
||||
{78CB2F39-B809-4A06-8329-8C0A19119D3D} = {10FBF193-D532-4CCF-B875-4C7091A7F6C2}
|
||||
{30A05C4D-F5FD-421C-A864-17A64BDEAA75} = {10FBF193-D532-4CCF-B875-4C7091A7F6C2}
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E} = {A17D34F1-7E3E-4841-818D-3B7C6F5AF829}
|
||||
{60F89955-91C6-3A36-8000-13C592FEC2DF} = {F0C19EFA-EDD0-43F2-97C1-18E865E96B4E}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
+10
-6
@@ -112,6 +112,7 @@ ${LLVM_INCLUDE_DIRS}
|
||||
"${RPCS3_SRC_DIR}/.."
|
||||
"${RPCS3_SRC_DIR}/../asmjit/src/asmjit"
|
||||
"${RPCS3_SRC_DIR}/../glm"
|
||||
"${RPCS3_SRC_DIR}/../libpng"
|
||||
"${RPCS3_SRC_DIR}/../GSL/include"
|
||||
"${RPCS3_SRC_DIR}/../rsx_program_decompiler/rsx_decompiler"
|
||||
"${RPCS3_SRC_DIR}/../rsx_program_decompiler/shader_code"
|
||||
@@ -140,7 +141,10 @@ else()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
link_directories("${RPCS3_SRC_DIR}/../asmjit/" "${RPCS3_SRC_DIR}/../minidx12/")
|
||||
link_directories(
|
||||
"${RPCS3_SRC_DIR}/../asmjit/"
|
||||
"${RPCS3_SRC_DIR}/../minidx12/"
|
||||
)
|
||||
|
||||
if(MSVC OR NOT WIN32)
|
||||
link_directories("${RPCS3_SRC_DIR}/../ffmpeg/${PLATFORM_ARCH}/lib")
|
||||
@@ -185,14 +189,14 @@ if(WIN32) # I'm not sure we need all of these libs, but we link them in vs
|
||||
else()
|
||||
target_link_libraries(rpcs3 dxgi.lib d2d1.lib dwrite.lib)
|
||||
endif()
|
||||
target_link_libraries(rpcs3 asmjit.lib avformat.lib avcodec.lib avutil.lib swresample.lib swscale.lib ${wxWidgets_LIBRARIES} ${OPENAL_LIBRARY} ${ADDITIONAL_LIBS})
|
||||
target_link_libraries(rpcs3 asmjit.lib avformat.lib avcodec.lib avutil.lib swresample.lib swscale.lib png16_static ${wxWidgets_LIBRARIES} ${OPENAL_LIBRARY} ${ADDITIONAL_LIBS})
|
||||
else()
|
||||
if(LLVM_FOUND)
|
||||
target_link_libraries(rpcs3 asmjit.a ${wxWidgets_LIBRARIES} ${OPENAL_LIBRARY} ${GLEW_LIBRARY} ${OPENGL_LIBRARIES})
|
||||
target_link_libraries(rpcs3 libavformat.a libavcodec.a libavutil.a libswresample.a libswscale.a ${ZLIB_LIBRARIES} ${LLVM_LIBS} ${ADDITIONAL_LIBS})
|
||||
target_link_libraries(rpcs3 asmjit.a ${wxWidgets_LIBRARIES} ${OPENAL_LIBRARY} ${GLEW_LIBRARY} ${OPENGL_LIBRARIES})
|
||||
target_link_libraries(rpcs3 libavformat.a libavcodec.a libavutil.a libswresample.a libswscale.a png16_static ${ZLIB_LIBRARIES} ${LLVM_LIBS} ${ADDITIONAL_LIBS})
|
||||
else()
|
||||
target_link_libraries(rpcs3 asmjit.a ${wxWidgets_LIBRARIES} ${OPENAL_LIBRARY} ${GLEW_LIBRARY} ${OPENGL_LIBRARIES})
|
||||
target_link_libraries(rpcs3 libavformat.a libavcodec.a libavutil.a libswresample.a libswscale.a ${ZLIB_LIBRARIES} ${ADDITIONAL_LIBS})
|
||||
target_link_libraries(rpcs3 asmjit.a ${wxWidgets_LIBRARIES} ${OPENAL_LIBRARY} ${GLEW_LIBRARY} ${OPENGL_LIBRARIES})
|
||||
target_link_libraries(rpcs3 libavformat.a libavcodec.a libavutil.a libswresample.a libswscale.a png16_static ${ZLIB_LIBRARIES} ${ADDITIONAL_LIBS})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
@@ -17,18 +17,45 @@ struct vfsStream
|
||||
|
||||
virtual u64 Write(const void* src, u64 count) = 0;
|
||||
|
||||
template<typename T> force_inline bool SWrite(const T& data, u64 count = sizeof(T))
|
||||
template<typename T>
|
||||
force_inline bool SWrite(const T& data, u64 count = sizeof(T))
|
||||
{
|
||||
return Write(&data, count) == count;
|
||||
}
|
||||
|
||||
virtual u64 Read(void* dst, u64 count) = 0;
|
||||
|
||||
template<typename T> force_inline bool SRead(T& data, u64 count = sizeof(T))
|
||||
template<typename T>
|
||||
force_inline bool SRead(T& data, u64 count = sizeof(T))
|
||||
{
|
||||
return Read(&data, count) == count;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool VWrite(const std::vector<T>& vec)
|
||||
{
|
||||
return IsOpened() && Write(vec.data(), vec.size() * sizeof(T)) == vec.size() * sizeof(T);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::vector<T> VRead()
|
||||
{
|
||||
std::vector<T> result;
|
||||
if (IsOpened() == false)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
result.resize(GetSize() / sizeof(T));
|
||||
|
||||
if (Seek(0) == -1 || Read(result.data(), result.size() * sizeof(T)) != result.size() * sizeof(T))
|
||||
{
|
||||
result.clear();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
virtual u64 Seek(s64 offset, fs::seek_mode whence = fs::seek_set) = 0;
|
||||
|
||||
virtual u64 Tell() const = 0;
|
||||
|
||||
@@ -335,7 +335,7 @@ public:
|
||||
u32 ctrl = (vmfprog.outputFromH0 ? 0 : 0x40) | (vmfprog.depthReplace ? 0xe : 0);
|
||||
std::vector<texture_dimension> td;
|
||||
RSXFragmentProgram prog;
|
||||
prog.size = 0, prog.addr = ptr + vmprog.ucode, prog.offset = 0, prog.ctrl = ctrl;
|
||||
prog.size = 0, prog.addr = vm::base(ptr + vmprog.ucode), prog.offset = 0, prog.ctrl = ctrl;
|
||||
GLFragmentDecompilerThread(m_glsl_shader, param_array, prog, size).Task();
|
||||
vm::close();
|
||||
}
|
||||
|
||||
@@ -30,32 +30,29 @@ namespace
|
||||
|
||||
void write_vertex_array_data_to_buffer(void *buffer, u32 first, u32 count, size_t index, const rsx::data_array_format_info &vertex_array_desc)
|
||||
{
|
||||
assert(vertex_array_desc.size > 0);
|
||||
|
||||
if (vertex_array_desc.frequency > 1)
|
||||
LOG_ERROR(RSX, "%s: frequency is not null (%d, index=%d)", __FUNCTION__, vertex_array_desc.frequency, index);
|
||||
Expects(vertex_array_desc.size > 0);
|
||||
|
||||
u32 base_offset = rsx::method_registers[NV4097_SET_VERTEX_DATA_BASE_OFFSET];
|
||||
u32 offset = rsx::method_registers[NV4097_SET_VERTEX_DATA_ARRAY_OFFSET + index];
|
||||
u32 address = rsx::get_address(offset & 0x7fffffff, offset >> 31);
|
||||
u32 address = base_offset + rsx::get_address(offset & 0x7fffffff, offset >> 31);
|
||||
|
||||
u32 element_size = rsx::get_vertex_type_size_on_host(vertex_array_desc.type, vertex_array_desc.size);
|
||||
|
||||
u32 base_offset = rsx::method_registers[NV4097_SET_VERTEX_DATA_BASE_OFFSET];
|
||||
u32 base_index = rsx::method_registers[NV4097_SET_VERTEX_DATA_BASE_INDEX];
|
||||
|
||||
for (u32 i = 0; i < count; ++i)
|
||||
{
|
||||
auto src = vm::ps3::_ptr<const u8>(address + base_offset + vertex_array_desc.stride * (first + i + base_index));
|
||||
auto src = vm::ps3::_ptr<const u8>(address + vertex_array_desc.stride * (first + i + base_index));
|
||||
u8* dst = (u8*)buffer + i * element_size;
|
||||
|
||||
switch (vertex_array_desc.type)
|
||||
{
|
||||
case Vertex_base_type::ub:
|
||||
case rsx::vertex_base_type::ub:
|
||||
memcpy(dst, src, vertex_array_desc.size);
|
||||
break;
|
||||
|
||||
case Vertex_base_type::s1:
|
||||
case Vertex_base_type::sf:
|
||||
case rsx::vertex_base_type::s1:
|
||||
case rsx::vertex_base_type::sf:
|
||||
{
|
||||
auto* c_src = (const be_t<u16>*)src;
|
||||
u16* c_dst = (u16*)dst;
|
||||
@@ -65,13 +62,13 @@ void write_vertex_array_data_to_buffer(void *buffer, u32 first, u32 count, size_
|
||||
*c_dst++ = *c_src++;
|
||||
}
|
||||
if (vertex_array_desc.size * sizeof(u16) < element_size)
|
||||
*c_dst++ = 0x3800;
|
||||
*c_dst++ = 0x3c00;
|
||||
break;
|
||||
}
|
||||
|
||||
case Vertex_base_type::f:
|
||||
case Vertex_base_type::s32k:
|
||||
case Vertex_base_type::ub256:
|
||||
case rsx::vertex_base_type::f:
|
||||
case rsx::vertex_base_type::s32k:
|
||||
case rsx::vertex_base_type::ub256:
|
||||
{
|
||||
auto* c_src = (const be_t<u32>*)src;
|
||||
u32* c_dst = (u32*)dst;
|
||||
@@ -82,7 +79,7 @@ void write_vertex_array_data_to_buffer(void *buffer, u32 first, u32 count, size_
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Vertex_base_type::cmp:
|
||||
case rsx::vertex_base_type::cmp:
|
||||
{
|
||||
auto* c_src = (const be_t<u32>*)src;
|
||||
const auto& decoded_vector = decode_cmp_vector(*c_src);
|
||||
@@ -244,21 +241,21 @@ std::tuple<T, T> expand_indexed_quads(gsl::span<to_be_t<const T>> src, gsl::span
|
||||
}
|
||||
|
||||
// Only handle quads and triangle fan now
|
||||
bool is_primitive_native(Primitive_type m_draw_mode)
|
||||
bool is_primitive_native(rsx::primitive_type draw_mode)
|
||||
{
|
||||
switch (m_draw_mode)
|
||||
switch (draw_mode)
|
||||
{
|
||||
case Primitive_type::points:
|
||||
case Primitive_type::lines:
|
||||
case Primitive_type::line_loop:
|
||||
case Primitive_type::line_strip:
|
||||
case Primitive_type::triangles:
|
||||
case Primitive_type::triangle_strip:
|
||||
case Primitive_type::quad_strip:
|
||||
case rsx::primitive_type::points:
|
||||
case rsx::primitive_type::lines:
|
||||
case rsx::primitive_type::line_loop:
|
||||
case rsx::primitive_type::line_strip:
|
||||
case rsx::primitive_type::triangles:
|
||||
case rsx::primitive_type::triangle_strip:
|
||||
case rsx::primitive_type::quad_strip:
|
||||
return true;
|
||||
case Primitive_type::polygon:
|
||||
case Primitive_type::triangle_fan:
|
||||
case Primitive_type::quads:
|
||||
case rsx::primitive_type::polygon:
|
||||
case rsx::primitive_type::triangle_fan:
|
||||
case rsx::primitive_type::quads:
|
||||
return false;
|
||||
}
|
||||
throw new EXCEPTION("Wrong primitive type");
|
||||
@@ -269,41 +266,41 @@ bool is_primitive_native(Primitive_type m_draw_mode)
|
||||
* see http://www.gamedev.net/page/resources/_/technical/graphics-programming-and-theory/polygon-triangulation-r3334
|
||||
*/
|
||||
|
||||
size_t get_index_count(Primitive_type m_draw_mode, unsigned initial_index_count)
|
||||
size_t get_index_count(rsx::primitive_type draw_mode, unsigned initial_index_count)
|
||||
{
|
||||
// Index count
|
||||
if (is_primitive_native(m_draw_mode))
|
||||
if (is_primitive_native(draw_mode))
|
||||
return initial_index_count;
|
||||
|
||||
switch (m_draw_mode)
|
||||
switch (draw_mode)
|
||||
{
|
||||
case Primitive_type::polygon:
|
||||
case Primitive_type::triangle_fan:
|
||||
case rsx::primitive_type::polygon:
|
||||
case rsx::primitive_type::triangle_fan:
|
||||
return (initial_index_count - 2) * 3;
|
||||
case Primitive_type::quads:
|
||||
case rsx::primitive_type::quads:
|
||||
return (6 * initial_index_count) / 4;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
size_t get_index_type_size(Index_array_type type)
|
||||
size_t get_index_type_size(rsx::index_array_type type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case Index_array_type::unsigned_16b: return 2;
|
||||
case Index_array_type::unsigned_32b: return 4;
|
||||
case rsx::index_array_type::u16: return sizeof(u16);
|
||||
case rsx::index_array_type::u32: return sizeof(u32);
|
||||
}
|
||||
throw new EXCEPTION("Wrong index type");
|
||||
}
|
||||
|
||||
void write_index_array_for_non_indexed_non_native_primitive_to_buffer(char* dst, Primitive_type draw_mode, unsigned first, unsigned count)
|
||||
void write_index_array_for_non_indexed_non_native_primitive_to_buffer(char* dst, rsx::primitive_type draw_mode, unsigned first, unsigned count)
|
||||
{
|
||||
unsigned short *typedDst = (unsigned short *)(dst);
|
||||
switch (draw_mode)
|
||||
{
|
||||
case Primitive_type::triangle_fan:
|
||||
case Primitive_type::polygon:
|
||||
case rsx::primitive_type::triangle_fan:
|
||||
case rsx::primitive_type::polygon:
|
||||
for (unsigned i = 0; i < (count - 2); i++)
|
||||
{
|
||||
typedDst[3 * i] = first;
|
||||
@@ -311,7 +308,7 @@ void write_index_array_for_non_indexed_non_native_primitive_to_buffer(char* dst,
|
||||
typedDst[3 * i + 2] = i + 2;
|
||||
}
|
||||
return;
|
||||
case Primitive_type::quads:
|
||||
case rsx::primitive_type::quads:
|
||||
for (unsigned i = 0; i < count / 4; i++)
|
||||
{
|
||||
// First triangle
|
||||
@@ -324,13 +321,13 @@ void write_index_array_for_non_indexed_non_native_primitive_to_buffer(char* dst,
|
||||
typedDst[6 * i + 5] = 4 * i + first;
|
||||
}
|
||||
return;
|
||||
case Primitive_type::points:
|
||||
case Primitive_type::lines:
|
||||
case Primitive_type::line_loop:
|
||||
case Primitive_type::line_strip:
|
||||
case Primitive_type::triangles:
|
||||
case Primitive_type::triangle_strip:
|
||||
case Primitive_type::quad_strip:
|
||||
case rsx::primitive_type::points:
|
||||
case rsx::primitive_type::lines:
|
||||
case rsx::primitive_type::line_loop:
|
||||
case rsx::primitive_type::line_strip:
|
||||
case rsx::primitive_type::triangles:
|
||||
case rsx::primitive_type::triangle_strip:
|
||||
case rsx::primitive_type::quad_strip:
|
||||
throw new EXCEPTION("Native primitive type doesn't require expansion");
|
||||
}
|
||||
}
|
||||
@@ -338,14 +335,14 @@ void write_index_array_for_non_indexed_non_native_primitive_to_buffer(char* dst,
|
||||
// TODO: Unify indexed and non indexed primitive expansion ?
|
||||
|
||||
template<typename T>
|
||||
std::tuple<T, T> write_index_array_data_to_buffer_impl(gsl::span<T, gsl::dynamic_range> dst, Primitive_type m_draw_mode, const std::vector<std::pair<u32, u32> > &first_count_arguments)
|
||||
std::tuple<T, T> write_index_array_data_to_buffer_impl(gsl::span<T, gsl::dynamic_range> dst, rsx::primitive_type draw_mode, const std::vector<std::pair<u32, u32> > &first_count_arguments)
|
||||
{
|
||||
u32 address = rsx::get_address(rsx::method_registers[NV4097_SET_INDEX_ARRAY_ADDRESS], rsx::method_registers[NV4097_SET_INDEX_ARRAY_DMA] & 0xf);
|
||||
Index_array_type type = to_index_array_type(rsx::method_registers[NV4097_SET_INDEX_ARRAY_DMA] >> 4);
|
||||
rsx::index_array_type type = rsx::to_index_array_type(rsx::method_registers[NV4097_SET_INDEX_ARRAY_DMA] >> 4);
|
||||
|
||||
u32 type_size = gsl::narrow<u32>(get_index_type_size(type));
|
||||
|
||||
Expects(rsx::method_registers[NV4097_SET_VERTEX_DATA_BASE_OFFSET] == 0);
|
||||
|
||||
Expects(rsx::method_registers[NV4097_SET_VERTEX_DATA_BASE_INDEX] == 0);
|
||||
|
||||
bool is_primitive_restart_enabled = !!rsx::method_registers[NV4097_SET_RESTART_INDEX_ENABLE];
|
||||
@@ -362,40 +359,40 @@ std::tuple<T, T> write_index_array_data_to_buffer_impl(gsl::span<T, gsl::dynamic
|
||||
u32 count = std::get<0>(first_count_arguments.back()) + std::get<1>(first_count_arguments.back()) - first;
|
||||
auto ptr = vm::ps3::_ptr<const T>(address + first * type_size);
|
||||
|
||||
switch (m_draw_mode)
|
||||
switch (draw_mode)
|
||||
{
|
||||
case Primitive_type::points:
|
||||
case Primitive_type::lines:
|
||||
case Primitive_type::line_loop:
|
||||
case Primitive_type::line_strip:
|
||||
case Primitive_type::triangles:
|
||||
case Primitive_type::triangle_strip:
|
||||
case Primitive_type::quad_strip:
|
||||
case rsx::primitive_type::points:
|
||||
case rsx::primitive_type::lines:
|
||||
case rsx::primitive_type::line_loop:
|
||||
case rsx::primitive_type::line_strip:
|
||||
case rsx::primitive_type::triangles:
|
||||
case rsx::primitive_type::triangle_strip:
|
||||
case rsx::primitive_type::quad_strip:
|
||||
return upload_untouched<T>({ ptr, count }, dst, is_primitive_restart_enabled, primitive_restart_index);
|
||||
case Primitive_type::polygon:
|
||||
case Primitive_type::triangle_fan:
|
||||
case rsx::primitive_type::polygon:
|
||||
case rsx::primitive_type::triangle_fan:
|
||||
return expand_indexed_triangle_fan<T>({ ptr, count }, dst, is_primitive_restart_enabled, primitive_restart_index);
|
||||
case Primitive_type::quads:
|
||||
case rsx::primitive_type::quads:
|
||||
return expand_indexed_quads<T>({ ptr, count }, dst, is_primitive_restart_enabled, primitive_restart_index);
|
||||
}
|
||||
|
||||
throw new EXCEPTION("Unknow draw mode");
|
||||
}
|
||||
|
||||
std::tuple<u32, u32> write_index_array_data_to_buffer(gsl::span<u32, gsl::dynamic_range> dst, Primitive_type m_draw_mode, const std::vector<std::pair<u32, u32> > &first_count_arguments)
|
||||
std::tuple<u32, u32> write_index_array_data_to_buffer(gsl::span<u32, gsl::dynamic_range> dst, rsx::primitive_type draw_mode, const std::vector<std::pair<u32, u32> > &first_count_arguments)
|
||||
{
|
||||
return write_index_array_data_to_buffer_impl(dst, m_draw_mode, first_count_arguments);
|
||||
return write_index_array_data_to_buffer_impl(dst, draw_mode, first_count_arguments);
|
||||
}
|
||||
|
||||
std::tuple<u16, u16> write_index_array_data_to_buffer(gsl::span<u16, gsl::dynamic_range> dst, Primitive_type m_draw_mode, const std::vector<std::pair<u32, u32> > &first_count_arguments)
|
||||
std::tuple<u16, u16> write_index_array_data_to_buffer(gsl::span<u16, gsl::dynamic_range> dst, rsx::primitive_type draw_mode, const std::vector<std::pair<u32, u32> > &first_count_arguments)
|
||||
{
|
||||
return write_index_array_data_to_buffer_impl(dst, m_draw_mode, first_count_arguments);
|
||||
return write_index_array_data_to_buffer_impl(dst, draw_mode, first_count_arguments);
|
||||
}
|
||||
|
||||
std::tuple<u32, u32> write_index_array_data_to_buffer_untouched(gsl::span<u32, gsl::dynamic_range> dst, const std::vector<std::pair<u32, u32> > &first_count_arguments)
|
||||
{
|
||||
u32 address = rsx::get_address(rsx::method_registers[NV4097_SET_INDEX_ARRAY_ADDRESS], rsx::method_registers[NV4097_SET_INDEX_ARRAY_DMA] & 0xf);
|
||||
Index_array_type type = to_index_array_type(rsx::method_registers[NV4097_SET_INDEX_ARRAY_DMA] >> 4);
|
||||
rsx::index_array_type type = rsx::to_index_array_type(rsx::method_registers[NV4097_SET_INDEX_ARRAY_DMA] >> 4);
|
||||
|
||||
u32 type_size = gsl::narrow<u32>(get_index_type_size(type));
|
||||
bool is_primitive_restart_enabled = !!rsx::method_registers[NV4097_SET_RESTART_INDEX_ENABLE];
|
||||
@@ -418,7 +415,7 @@ std::tuple<u32, u32> write_index_array_data_to_buffer_untouched(gsl::span<u32, g
|
||||
std::tuple<u16, u16> write_index_array_data_to_buffer_untouched(gsl::span<u16, gsl::dynamic_range> dst, const std::vector<std::pair<u32, u32> > &first_count_arguments)
|
||||
{
|
||||
u32 address = rsx::get_address(rsx::method_registers[NV4097_SET_INDEX_ARRAY_ADDRESS], rsx::method_registers[NV4097_SET_INDEX_ARRAY_DMA] & 0xf);
|
||||
Index_array_type type = to_index_array_type(rsx::method_registers[NV4097_SET_INDEX_ARRAY_DMA] >> 4);
|
||||
rsx::index_array_type type = rsx::to_index_array_type(rsx::method_registers[NV4097_SET_INDEX_ARRAY_DMA] >> 4);
|
||||
|
||||
u32 type_size = gsl::narrow<u32>(get_index_type_size(type));
|
||||
bool is_primitive_restart_enabled = !!rsx::method_registers[NV4097_SET_RESTART_INDEX_ENABLE];
|
||||
|
||||
@@ -11,25 +11,25 @@ void write_vertex_array_data_to_buffer(void *buffer, u32 first, u32 count, size_
|
||||
/*
|
||||
* If primitive mode is not supported and need to be emulated (using an index buffer) returns false.
|
||||
*/
|
||||
bool is_primitive_native(Primitive_type m_draw_mode);
|
||||
bool is_primitive_native(rsx::primitive_type m_draw_mode);
|
||||
|
||||
/**
|
||||
* Returns a fixed index count for emulated primitive, otherwise returns initial_index_count
|
||||
*/
|
||||
size_t get_index_count(Primitive_type m_draw_mode, unsigned initial_index_count);
|
||||
size_t get_index_count(rsx::primitive_type m_draw_mode, unsigned initial_index_count);
|
||||
|
||||
/**
|
||||
* Returns index type size in byte
|
||||
*/
|
||||
size_t get_index_type_size(Index_array_type type);
|
||||
size_t get_index_type_size(rsx::index_array_type type);
|
||||
|
||||
/**
|
||||
* Write count indexes using (first, first + count) ranges.
|
||||
* Returns min/max index found during the process.
|
||||
* The function expands index buffer for non native primitive type.
|
||||
*/
|
||||
std::tuple<u32, u32> write_index_array_data_to_buffer(gsl::span<u32, gsl::dynamic_range> dst, Primitive_type m_draw_mode, const std::vector<std::pair<u32, u32> > &first_count_arguments);
|
||||
std::tuple<u16, u16> write_index_array_data_to_buffer(gsl::span<u16, gsl::dynamic_range> dst, Primitive_type m_draw_mode, const std::vector<std::pair<u32, u32> > &first_count_arguments);
|
||||
std::tuple<u32, u32> write_index_array_data_to_buffer(gsl::span<u32, gsl::dynamic_range> dst, rsx::primitive_type draw_mode, const std::vector<std::pair<u32, u32> > &first_count_arguments);
|
||||
std::tuple<u16, u16> write_index_array_data_to_buffer(gsl::span<u16, gsl::dynamic_range> dst, rsx::primitive_type draw_mode, const std::vector<std::pair<u32, u32> > &first_count_arguments);
|
||||
|
||||
/**
|
||||
* Doesn't expand index
|
||||
@@ -40,7 +40,7 @@ std::tuple<u16, u16> write_index_array_data_to_buffer_untouched(gsl::span<u16, g
|
||||
/**
|
||||
* Write index data needed to emulate non indexed non native primitive mode.
|
||||
*/
|
||||
void write_index_array_for_non_indexed_non_native_primitive_to_buffer(char* dst, Primitive_type m_draw_mode, unsigned first, unsigned count);
|
||||
void write_index_array_for_non_indexed_non_native_primitive_to_buffer(char* dst, rsx::primitive_type draw_mode, unsigned first, unsigned count);
|
||||
|
||||
/**
|
||||
* Stream a 128 bits vector to dst.
|
||||
|
||||
@@ -5,12 +5,11 @@
|
||||
#include "FragmentProgramDecompiler.h"
|
||||
|
||||
FragmentProgramDecompiler::FragmentProgramDecompiler(const RSXFragmentProgram &prog, u32& size) :
|
||||
m_addr(prog.addr),
|
||||
m_prog(prog),
|
||||
m_size(size),
|
||||
m_const_index(0),
|
||||
m_location(0),
|
||||
m_ctrl(prog.ctrl),
|
||||
m_texture_dimensions(prog.texture_dimensions)
|
||||
m_ctrl(prog.ctrl)
|
||||
{
|
||||
m_size = 0;
|
||||
}
|
||||
@@ -114,7 +113,7 @@ std::string FragmentProgramDecompiler::AddConst()
|
||||
return name;
|
||||
}
|
||||
|
||||
auto data = vm::ps3::ptr<u32>::make(m_addr + m_size + 4 * SIZE_32(u32));
|
||||
auto data = (be_t<u32>*) ((char*)m_prog.addr + m_size + 4 * SIZE_32(u32));
|
||||
|
||||
m_offset = 2 * 4 * sizeof(u32);
|
||||
u32 x = GetData(data[0]);
|
||||
@@ -128,7 +127,23 @@ std::string FragmentProgramDecompiler::AddConst()
|
||||
|
||||
std::string FragmentProgramDecompiler::AddTex()
|
||||
{
|
||||
return m_parr.AddParam(PF_PARAM_UNIFORM, (m_texture_dimensions[dst.tex_num] == texture_dimension::texture_dimension_cubemap) ? "samplerCube" : "sampler2D", std::string("tex") + std::to_string(dst.tex_num));
|
||||
std::string sampler;
|
||||
switch (m_prog.get_texture_dimension(dst.tex_num))
|
||||
{
|
||||
case texture_dimension::texture_dimension_1d:
|
||||
sampler = "sampler1D";
|
||||
break;
|
||||
case texture_dimension::texture_dimension_cubemap:
|
||||
sampler = "samplerCube";
|
||||
break;
|
||||
case texture_dimension::texture_dimension_2d:
|
||||
sampler = "sampler2D";
|
||||
break;
|
||||
case texture_dimension::texture_dimension_3d:
|
||||
sampler = "sampler3D";
|
||||
break;
|
||||
}
|
||||
return m_parr.AddParam(PF_PARAM_UNIFORM, sampler, std::string("tex") + std::to_string(dst.tex_num));
|
||||
}
|
||||
|
||||
std::string FragmentProgramDecompiler::Format(const std::string& code)
|
||||
@@ -259,7 +274,7 @@ template<typename T> std::string FragmentProgramDecompiler::GetSRC(T src)
|
||||
{
|
||||
static const std::string reg_table[] =
|
||||
{
|
||||
"gl_Position",
|
||||
"gl_FragCoord",
|
||||
"diff_color", "spec_color",
|
||||
"fogc",
|
||||
"tc0", "tc1", "tc2", "tc3", "tc4", "tc5", "tc6", "tc7", "tc8", "tc9",
|
||||
@@ -340,7 +355,7 @@ bool FragmentProgramDecompiler::handle_sct(u32 opcode)
|
||||
switch (opcode)
|
||||
{
|
||||
case RSX_FP_OPCODE_ADD: SetDst("($0 + $1)"); return true;
|
||||
case RSX_FP_OPCODE_DIV: SetDst("($0 / $1)"); return true;
|
||||
case RSX_FP_OPCODE_DIV: SetDst("($0 / $1.xxxx)"); return true;
|
||||
// Note: DIVSQ is not IEEE compliant. divsq(0, 0) is 0 (Super Puzzle Fighter II Turbo HD Remix).
|
||||
// sqrt(x, 0) might be equal to some big value (in absolute) whose sign is sign(x) but it has to be proven.
|
||||
case RSX_FP_OPCODE_DIVSQ: SetDst("divsq_legacy($0, $1)"); return true;
|
||||
@@ -376,7 +391,7 @@ bool FragmentProgramDecompiler::handle_scb(u32 opcode)
|
||||
{
|
||||
case RSX_FP_OPCODE_ADD: SetDst("($0 + $1)"); return true;
|
||||
case RSX_FP_OPCODE_COS: SetDst("cos($0.xxxx)"); return true;
|
||||
case RSX_FP_OPCODE_DIV: SetDst("($0 / $1)"); return true;
|
||||
case RSX_FP_OPCODE_DIV: SetDst("($0 / $1.xxxx)"); return true;
|
||||
// Note: DIVSQ is not IEEE compliant. sqrt(0, 0) is 0 (Super Puzzle Fighter II Turbo HD Remix).
|
||||
// sqrt(x, 0) might be equal to some big value (in absolute) whose sign is sign(x) but it has to be proven.
|
||||
case RSX_FP_OPCODE_DIVSQ: SetDst("divsq_legacy($0, sqrt($1).xxxx)"); return true;
|
||||
@@ -389,7 +404,7 @@ bool FragmentProgramDecompiler::handle_scb(u32 opcode)
|
||||
case RSX_FP_OPCODE_EX2: SetDst("exp2($0.xxxx)"); return true;
|
||||
case RSX_FP_OPCODE_FLR: SetDst("floor($0)"); return true;
|
||||
case RSX_FP_OPCODE_FRC: SetDst(getFunction(FUNCTION::FUNCTION_FRACT)); return true;
|
||||
case RSX_FP_OPCODE_LIT: SetDst(getFloatTypeName(4) + "(1.0, $0.x, ($0.x > 0.0 ? exp($0.w * log2($0.y)) : 0.0), 1.0)"); return true;
|
||||
case RSX_FP_OPCODE_LIT: SetDst("lit_legacy($0)"); return true;
|
||||
case RSX_FP_OPCODE_LIF: SetDst(getFloatTypeName(4) + "(1.0, $0.y, ($0.y > 0 ? pow(2.0, $0.w) : 0.0), 1.0)"); return true;
|
||||
case RSX_FP_OPCODE_LRP: LOG_ERROR(RSX, "Unimplemented SCB instruction: LRP"); return true; // TODO: Is this in the right category?
|
||||
case RSX_FP_OPCODE_LG2: SetDst("log2($0.xxxx)"); return true;
|
||||
@@ -425,35 +440,37 @@ bool FragmentProgramDecompiler::handle_tex_srb(u32 opcode)
|
||||
case RSX_FP_OPCODE_NRM: SetDst("normalize($0)"); return true;
|
||||
case RSX_FP_OPCODE_BEM: LOG_ERROR(RSX, "Unimplemented TEX_SRB instruction: BEM"); return true;
|
||||
case RSX_FP_OPCODE_TEX:
|
||||
if (dst.tex_num >= m_texture_dimensions.size())
|
||||
switch (m_prog.get_texture_dimension(dst.tex_num))
|
||||
{
|
||||
SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_SAMPLE));
|
||||
case texture_dimension::texture_dimension_1d:
|
||||
SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_SAMPLE1D));
|
||||
return true;
|
||||
}
|
||||
switch (m_texture_dimensions[dst.tex_num])
|
||||
{
|
||||
case texture_dimension::texture_dimension_2d:
|
||||
SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_SAMPLE));
|
||||
SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_SAMPLE2D));
|
||||
return true;
|
||||
case texture_dimension::texture_dimension_cubemap:
|
||||
SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_CUBE_SAMPLE));
|
||||
SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_SAMPLECUBE));
|
||||
return true;
|
||||
case texture_dimension::texture_dimension_3d:
|
||||
SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_SAMPLE3D));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
case RSX_FP_OPCODE_TEXBEM: SetDst("texture($t, $0.xy, $1.x)"); return true;
|
||||
case RSX_FP_OPCODE_TXP:
|
||||
if (dst.tex_num >= m_texture_dimensions.size())
|
||||
switch (m_prog.get_texture_dimension(dst.tex_num))
|
||||
{
|
||||
SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_SAMPLE_PROJ));
|
||||
case texture_dimension::texture_dimension_1d:
|
||||
SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_SAMPLE1D_PROJ));
|
||||
return true;
|
||||
}
|
||||
switch (m_texture_dimensions[dst.tex_num])
|
||||
{
|
||||
case texture_dimension::texture_dimension_2d:
|
||||
SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_SAMPLE_PROJ));
|
||||
SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_SAMPLE2D_PROJ));
|
||||
return true;
|
||||
case texture_dimension::texture_dimension_cubemap:
|
||||
SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_CUBE_SAMPLE_PROJ));
|
||||
SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_SAMPLECUBE_PROJ));
|
||||
return true;
|
||||
case texture_dimension::texture_dimension_3d:
|
||||
SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_SAMPLE3D_PROJ));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -461,18 +478,19 @@ bool FragmentProgramDecompiler::handle_tex_srb(u32 opcode)
|
||||
case RSX_FP_OPCODE_TXD: LOG_ERROR(RSX, "Unimplemented TEX_SRB instruction: TXD"); return true;
|
||||
case RSX_FP_OPCODE_TXB: SetDst("texture($t, $0.xy, $1.x)"); return true;
|
||||
case RSX_FP_OPCODE_TXL:
|
||||
if (dst.tex_num >= m_texture_dimensions.size())
|
||||
switch (m_prog.get_texture_dimension(dst.tex_num))
|
||||
{
|
||||
SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_SAMPLE_LOD));
|
||||
case texture_dimension::texture_dimension_1d:
|
||||
SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_SAMPLE1D_LOD));
|
||||
return true;
|
||||
}
|
||||
switch (m_texture_dimensions[dst.tex_num])
|
||||
{
|
||||
case texture_dimension::texture_dimension_2d:
|
||||
SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_SAMPLE_LOD));
|
||||
SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_SAMPLE2D_LOD));
|
||||
return true;
|
||||
case texture_dimension::texture_dimension_cubemap:
|
||||
SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_CUBE_SAMPLE_LOD));
|
||||
SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_SAMPLECUBE_LOD));
|
||||
return true;
|
||||
case texture_dimension::texture_dimension_3d:
|
||||
SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_SAMPLE3D_LOD));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -487,7 +505,7 @@ bool FragmentProgramDecompiler::handle_tex_srb(u32 opcode)
|
||||
|
||||
std::string FragmentProgramDecompiler::Decompile()
|
||||
{
|
||||
auto data = vm::ps3::ptr<u32>::make(m_addr);
|
||||
auto data = (be_t<u32>*) m_prog.addr;
|
||||
m_size = 0;
|
||||
m_location = 0;
|
||||
m_loop_count = 0;
|
||||
|
||||
@@ -25,9 +25,7 @@ class FragmentProgramDecompiler
|
||||
SRC2 src2;
|
||||
|
||||
std::string main;
|
||||
u32 m_addr;
|
||||
u32& m_size;
|
||||
const std::vector<texture_dimension> m_texture_dimensions;
|
||||
u32 m_const_index;
|
||||
u32 m_offset;
|
||||
u32 m_location;
|
||||
@@ -76,6 +74,7 @@ class FragmentProgramDecompiler
|
||||
*/
|
||||
bool handle_tex_srb(u32 opcode);
|
||||
protected:
|
||||
const RSXFragmentProgram &m_prog;
|
||||
u32 m_ctrl;
|
||||
/** returns the type name of float vectors.
|
||||
*/
|
||||
|
||||
@@ -3,14 +3,14 @@
|
||||
|
||||
using namespace program_hash_util;
|
||||
|
||||
size_t vertex_program_hash::operator()(const std::vector<u32> &program) const
|
||||
size_t vertex_program_hash::operator()(const RSXVertexProgram &program) const
|
||||
{
|
||||
// 64-bit Fowler/Noll/Vo FNV-1a hash code
|
||||
size_t hash = 0xCBF29CE484222325ULL;
|
||||
const qword *instbuffer = (const qword*)program.data();
|
||||
const qword *instbuffer = (const qword*)program.data.data();
|
||||
size_t instIndex = 0;
|
||||
bool end = false;
|
||||
for (unsigned i = 0; i < program.size() / 4; i++)
|
||||
for (unsigned i = 0; i < program.data.size() / 4; i++)
|
||||
{
|
||||
const qword inst = instbuffer[instIndex];
|
||||
hash ^= inst.dword[0];
|
||||
@@ -22,13 +22,17 @@ size_t vertex_program_hash::operator()(const std::vector<u32> &program) const
|
||||
return hash;
|
||||
}
|
||||
|
||||
bool vertex_program_compare::operator()(const std::vector<u32> &binary1, const std::vector<u32> &binary2) const
|
||||
bool vertex_program_compare::operator()(const RSXVertexProgram &binary1, const RSXVertexProgram &binary2) const
|
||||
{
|
||||
if (binary1.size() != binary2.size()) return false;
|
||||
const qword *instBuffer1 = (const qword*)binary1.data();
|
||||
const qword *instBuffer2 = (const qword*)binary2.data();
|
||||
if (binary1.output_mask != binary2.output_mask)
|
||||
return false;
|
||||
if (binary1.rsx_vertex_inputs != binary2.rsx_vertex_inputs)
|
||||
return false;
|
||||
if (binary1.data.size() != binary2.data.size()) return false;
|
||||
const qword *instBuffer1 = (const qword*)binary1.data.data();
|
||||
const qword *instBuffer2 = (const qword*)binary2.data.data();
|
||||
size_t instIndex = 0;
|
||||
for (unsigned i = 0; i < binary1.size() / 4; i++)
|
||||
for (unsigned i = 0; i < binary1.data.size() / 4; i++)
|
||||
{
|
||||
const qword& inst1 = instBuffer1[instIndex];
|
||||
const qword& inst2 = instBuffer2[instIndex];
|
||||
@@ -70,11 +74,11 @@ size_t fragment_program_utils::get_fragment_program_ucode_size(void *ptr)
|
||||
}
|
||||
}
|
||||
|
||||
size_t fragment_program_hash::operator()(const void *program) const
|
||||
size_t fragment_program_hash::operator()(const RSXFragmentProgram& program) const
|
||||
{
|
||||
// 64-bit Fowler/Noll/Vo FNV-1a hash code
|
||||
size_t hash = 0xCBF29CE484222325ULL;
|
||||
const qword *instbuffer = (const qword*)program;
|
||||
const qword *instbuffer = (const qword*)program.addr;
|
||||
size_t instIndex = 0;
|
||||
while (true)
|
||||
{
|
||||
@@ -97,10 +101,15 @@ size_t fragment_program_hash::operator()(const void *program) const
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool fragment_program_compare::operator()(const void *binary1, const void *binary2) const
|
||||
bool fragment_program_compare::operator()(const RSXFragmentProgram& binary1, const RSXFragmentProgram& binary2) const
|
||||
{
|
||||
const qword *instBuffer1 = (const qword*)binary1;
|
||||
const qword *instBuffer2 = (const qword*)binary2;
|
||||
if (binary1.texture_dimensions != binary2.texture_dimensions || binary1.unnormalized_coords != binary2.unnormalized_coords ||
|
||||
binary1.height != binary2.height || binary1.origin_mode != binary2.origin_mode || binary1.pixel_center_mode != binary2.pixel_center_mode ||
|
||||
binary1.back_color_diffuse_output != binary2.back_color_diffuse_output || binary1.back_color_specular_output != binary2.back_color_specular_output ||
|
||||
binary1.front_back_color_enabled != binary2.front_back_color_enabled || binary1.alpha_func != binary2.alpha_func)
|
||||
return false;
|
||||
const qword *instBuffer1 = (const qword*)binary1.addr;
|
||||
const qword *instBuffer2 = (const qword*)binary2.addr;
|
||||
size_t instIndex = 0;
|
||||
while (true)
|
||||
{
|
||||
|
||||
@@ -23,12 +23,12 @@ namespace program_hash_util
|
||||
|
||||
struct vertex_program_hash
|
||||
{
|
||||
size_t operator()(const std::vector<u32> &program) const;
|
||||
size_t operator()(const RSXVertexProgram &program) const;
|
||||
};
|
||||
|
||||
struct vertex_program_compare
|
||||
{
|
||||
bool operator()(const std::vector<u32> &binary1, const std::vector<u32> &binary2) const;
|
||||
bool operator()(const RSXVertexProgram &binary1, const RSXVertexProgram &binary2) const;
|
||||
};
|
||||
|
||||
struct fragment_program_utils
|
||||
@@ -43,12 +43,12 @@ namespace program_hash_util
|
||||
|
||||
struct fragment_program_hash
|
||||
{
|
||||
size_t operator()(const void *program) const;
|
||||
size_t operator()(const RSXFragmentProgram &program) const;
|
||||
};
|
||||
|
||||
struct fragment_program_compare
|
||||
{
|
||||
bool operator()(const void *binary1, const void *binary2) const;
|
||||
bool operator()(const RSXFragmentProgram &binary1, const RSXFragmentProgram &binary2) const;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -75,8 +75,8 @@ class program_state_cache
|
||||
using vertex_program_type = typename backend_traits::vertex_program_type;
|
||||
using fragment_program_type = typename backend_traits::fragment_program_type;
|
||||
|
||||
using binary_to_vertex_program = std::unordered_map<std::vector<u32>, vertex_program_type, program_hash_util::vertex_program_hash, program_hash_util::vertex_program_compare> ;
|
||||
using binary_to_fragment_program = std::unordered_map<void *, fragment_program_type, program_hash_util::fragment_program_hash, program_hash_util::fragment_program_compare>;
|
||||
using binary_to_vertex_program = std::unordered_map<RSXVertexProgram, vertex_program_type, program_hash_util::vertex_program_hash, program_hash_util::vertex_program_compare> ;
|
||||
using binary_to_fragment_program = std::unordered_map<RSXFragmentProgram, fragment_program_type, program_hash_util::fragment_program_hash, program_hash_util::fragment_program_compare>;
|
||||
|
||||
|
||||
struct pipeline_key
|
||||
@@ -115,13 +115,13 @@ private:
|
||||
/// bool here to inform that the program was preexisting.
|
||||
std::tuple<const vertex_program_type&, bool> search_vertex_program(const RSXVertexProgram& rsx_vp)
|
||||
{
|
||||
const auto& I = m_vertex_shader_cache.find(rsx_vp.data);
|
||||
const auto& I = m_vertex_shader_cache.find(rsx_vp);
|
||||
if (I != m_vertex_shader_cache.end())
|
||||
{
|
||||
return std::forward_as_tuple(I->second, true);
|
||||
}
|
||||
LOG_NOTICE(RSX, "VP not found in buffer!");
|
||||
vertex_program_type& new_shader = m_vertex_shader_cache[rsx_vp.data];
|
||||
vertex_program_type& new_shader = m_vertex_shader_cache[rsx_vp];
|
||||
backend_traits::recompile_vertex_program(rsx_vp, new_shader, m_next_id++);
|
||||
|
||||
return std::forward_as_tuple(new_shader, false);
|
||||
@@ -130,16 +130,18 @@ private:
|
||||
/// bool here to inform that the program was preexisting.
|
||||
std::tuple<const fragment_program_type&, bool> search_fragment_program(const RSXFragmentProgram& rsx_fp)
|
||||
{
|
||||
const auto& I = m_fragment_shader_cache.find(vm::base(rsx_fp.addr));
|
||||
const auto& I = m_fragment_shader_cache.find(rsx_fp);
|
||||
if (I != m_fragment_shader_cache.end())
|
||||
{
|
||||
return std::forward_as_tuple(I->second, true);
|
||||
}
|
||||
LOG_NOTICE(RSX, "FP not found in buffer!");
|
||||
size_t fragment_program_size = program_hash_util::fragment_program_utils::get_fragment_program_ucode_size(vm::base(rsx_fp.addr));
|
||||
size_t fragment_program_size = program_hash_util::fragment_program_utils::get_fragment_program_ucode_size(rsx_fp.addr);
|
||||
gsl::not_null<void*> fragment_program_ucode_copy = malloc(fragment_program_size);
|
||||
std::memcpy(fragment_program_ucode_copy, vm::base(rsx_fp.addr), fragment_program_size);
|
||||
fragment_program_type &new_shader = m_fragment_shader_cache[fragment_program_ucode_copy];
|
||||
std::memcpy(fragment_program_ucode_copy, rsx_fp.addr, fragment_program_size);
|
||||
RSXFragmentProgram new_fp_key = rsx_fp;
|
||||
new_fp_key.addr = fragment_program_ucode_copy;
|
||||
fragment_program_type &new_shader = m_fragment_shader_cache[new_fp_key];
|
||||
backend_traits::recompile_fragment_program(rsx_fp, new_shader, m_next_id++);
|
||||
|
||||
return std::forward_as_tuple(new_shader, false);
|
||||
@@ -147,19 +149,25 @@ private:
|
||||
|
||||
public:
|
||||
program_state_cache() = default;
|
||||
~program_state_cache() = default;
|
||||
~program_state_cache()
|
||||
{
|
||||
for (auto& pair : m_fragment_shader_cache)
|
||||
{
|
||||
free(pair.first.addr);
|
||||
}
|
||||
};
|
||||
|
||||
const vertex_program_type& get_transform_program(const RSXVertexProgram& rsx_vp) const
|
||||
{
|
||||
auto I = m_vertex_shader_cache.find(rsx_vp.data);
|
||||
if (I == m_vertex_shader_cache.end())
|
||||
auto I = m_vertex_shader_cache.find(rsx_vp);
|
||||
if (I != m_vertex_shader_cache.end())
|
||||
return I->second;
|
||||
throw new EXCEPTION("Trying to get unknow transform program");
|
||||
}
|
||||
|
||||
const fragment_program_type& get_shader_program(const RSXFragmentProgram& rsx_fp) const
|
||||
{
|
||||
auto I = m_fragment_shader_cache.find(vm::base(rsx_fp.addr));
|
||||
auto I = m_fragment_shader_cache.find(rsx_fp);
|
||||
if (I != m_fragment_shader_cache.end())
|
||||
return I->second;
|
||||
throw new EXCEPTION("Trying to get unknow shader program");
|
||||
@@ -200,7 +208,7 @@ public:
|
||||
|
||||
size_t get_fragment_constants_buffer_size(const RSXFragmentProgram &fragmentShader) const
|
||||
{
|
||||
const auto I = m_fragment_shader_cache.find(vm::base(fragmentShader.addr));
|
||||
const auto I = m_fragment_shader_cache.find(fragmentShader);
|
||||
if (I != m_fragment_shader_cache.end())
|
||||
return I->second.FragmentConstantOffsetCache.size() * 4 * sizeof(float);
|
||||
LOG_ERROR(RSX, "Can't retrieve constant offset cache");
|
||||
@@ -209,7 +217,7 @@ public:
|
||||
|
||||
void fill_fragment_constans_buffer(gsl::span<f32, gsl::dynamic_range> dst_buffer, const RSXFragmentProgram &fragment_program) const
|
||||
{
|
||||
const auto I = m_fragment_shader_cache.find(vm::base(fragment_program.addr));
|
||||
const auto I = m_fragment_shader_cache.find(fragment_program);
|
||||
if (I == m_fragment_shader_cache.end())
|
||||
return;
|
||||
__m128i mask = _mm_set_epi8(0xE, 0xF, 0xC, 0xD,
|
||||
@@ -222,11 +230,16 @@ public:
|
||||
size_t offset = 0;
|
||||
for (size_t offset_in_fragment_program : I->second.FragmentConstantOffsetCache)
|
||||
{
|
||||
void *data = vm::base(fragment_program.addr + (u32)offset_in_fragment_program);
|
||||
void *data = (char*)fragment_program.addr + (u32)offset_in_fragment_program;
|
||||
const __m128i &vector = _mm_loadu_si128((__m128i*)data);
|
||||
const __m128i &shuffled_vector = _mm_shuffle_epi8(vector, mask);
|
||||
_mm_stream_si128((__m128i*)dst_buffer.subspan(offset, 4).data(), shuffled_vector);
|
||||
offset += sizeof(f32);
|
||||
}
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
m_storage.clear();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -13,12 +13,18 @@ enum class FUNCTION {
|
||||
FUNCTION_FRACT,
|
||||
FUNCTION_DFDX,
|
||||
FUNCTION_DFDY,
|
||||
FUNCTION_TEXTURE_SAMPLE,
|
||||
FUNCTION_TEXTURE_SAMPLE_PROJ,
|
||||
FUNCTION_TEXTURE_SAMPLE_LOD,
|
||||
FUNCTION_TEXTURE_CUBE_SAMPLE,
|
||||
FUNCTION_TEXTURE_CUBE_SAMPLE_PROJ,
|
||||
FUNCTION_TEXTURE_CUBE_SAMPLE_LOD,
|
||||
FUNCTION_TEXTURE_SAMPLE1D,
|
||||
FUNCTION_TEXTURE_SAMPLE1D_PROJ,
|
||||
FUNCTION_TEXTURE_SAMPLE1D_LOD,
|
||||
FUNCTION_TEXTURE_SAMPLE2D,
|
||||
FUNCTION_TEXTURE_SAMPLE2D_PROJ,
|
||||
FUNCTION_TEXTURE_SAMPLE2D_LOD,
|
||||
FUNCTION_TEXTURE_SAMPLECUBE,
|
||||
FUNCTION_TEXTURE_SAMPLECUBE_PROJ,
|
||||
FUNCTION_TEXTURE_SAMPLECUBE_LOD,
|
||||
FUNCTION_TEXTURE_SAMPLE3D,
|
||||
FUNCTION_TEXTURE_SAMPLE3D_PROJ,
|
||||
FUNCTION_TEXTURE_SAMPLE3D_LOD,
|
||||
};
|
||||
|
||||
enum class COMPARE {
|
||||
|
||||
@@ -14,9 +14,9 @@ namespace
|
||||
struct texel_rgba
|
||||
{
|
||||
template<size_t block_size>
|
||||
static void copy_mipmap_level(void *dst, void *src, size_t row_count, size_t width_in_block, size_t dst_pitch_in_block, size_t src_pitch_in_block)
|
||||
static void copy_mipmap_level(void *dst, void *src, u16 row_count, u16 width_in_block, u16 depth, size_t dst_pitch_in_block, size_t src_pitch_in_block)
|
||||
{
|
||||
for (unsigned row = 0; row < row_count; row++)
|
||||
for (unsigned row = 0; row < row_count * depth; row++)
|
||||
memcpy((char*)dst + row * dst_pitch_in_block * block_size, (char*)src + row * src_pitch_in_block * block_size, width_in_block * block_size);
|
||||
}
|
||||
};
|
||||
@@ -28,13 +28,13 @@ struct texel_rgba
|
||||
struct texel_16b_swizzled
|
||||
{
|
||||
template<size_t block_size>
|
||||
static void copy_mipmap_level(void *dst, void *src, size_t row_count, size_t width_in_block, size_t dst_pitch_in_block, size_t src_pitch_in_block)
|
||||
static void copy_mipmap_level(void *dst, void *src, u16 row_count, u16 width_in_block, u16 depth, size_t dst_pitch_in_block, size_t src_pitch_in_block)
|
||||
{
|
||||
u16 *castedSrc = static_cast<u16*>(src), *castedDst = static_cast<u16*>(dst);
|
||||
|
||||
std::unique_ptr<u16[]> temp_swizzled(new u16[row_count * width_in_block]);
|
||||
rsx::convert_linear_swizzle<u16>(castedSrc, temp_swizzled.get(), src_pitch_in_block, row_count, true);
|
||||
for (unsigned row = 0; row < row_count; row++)
|
||||
for (unsigned row = 0; row < row_count * depth; row++)
|
||||
for (int j = 0; j < width_in_block; j++)
|
||||
{
|
||||
u16 tmp = temp_swizzled[row * src_pitch_in_block + j];
|
||||
@@ -49,14 +49,14 @@ struct texel_16b_swizzled
|
||||
struct texel_rgba_swizzled
|
||||
{
|
||||
template<size_t block_size>
|
||||
static void copy_mipmap_level(void *dst, void *src, size_t row_count, size_t width_in_block, size_t dst_pitch_in_block, size_t src_pitch_in_block)
|
||||
static void copy_mipmap_level(void *dst, void *src, u16 row_count, u16 width_in_block, u16 depth, size_t dst_pitch_in_block, size_t src_pitch_in_block)
|
||||
{
|
||||
u32 *castedSrc, *castedDst;
|
||||
castedSrc = (u32*)src;
|
||||
castedDst = (u32*)dst ;
|
||||
std::unique_ptr<u32[]> temp_swizzled(new u32[src_pitch_in_block * row_count]);
|
||||
rsx::convert_linear_swizzle<u32>(castedSrc, temp_swizzled.get(), src_pitch_in_block, row_count, true);
|
||||
for (unsigned row = 0; row < row_count; row++)
|
||||
for (unsigned row = 0; row < row_count * depth; row++)
|
||||
memcpy((char*)dst + row * dst_pitch_in_block * block_size, (char*)temp_swizzled.get() + row * src_pitch_in_block * block_size, width_in_block * block_size);
|
||||
}
|
||||
};
|
||||
@@ -67,9 +67,9 @@ struct texel_rgba_swizzled
|
||||
*/
|
||||
struct texel_bc_format {
|
||||
template<size_t block_size>
|
||||
static void copy_mipmap_level(void *dst, void *src, size_t row_count, size_t width_in_block, size_t dst_pitch_in_block, size_t src_pitch_in_block)
|
||||
static void copy_mipmap_level(void *dst, void *src, u16 row_count, u16 width_in_block, u16 depth, size_t dst_pitch_in_block, size_t src_pitch_in_block)
|
||||
{
|
||||
for (unsigned row = 0; row < row_count; row++)
|
||||
for (unsigned row = 0; row < row_count * depth; row++)
|
||||
memcpy((char*)dst + row * dst_pitch_in_block * block_size, (char*)src + row * src_pitch_in_block * block_size, width_in_block * block_size);
|
||||
}
|
||||
};
|
||||
@@ -79,11 +79,11 @@ struct texel_bc_format {
|
||||
*/
|
||||
struct texel_16b_format {
|
||||
template<size_t block_size>
|
||||
static void copy_mipmap_level(void *dst, void *src, size_t row_count, size_t width_in_block, size_t dst_pitch_in_block, size_t src_pitch_in_block)
|
||||
static void copy_mipmap_level(void *dst, void *src, u16 row_count, u16 width_in_block, u16 depth, size_t dst_pitch_in_block, size_t src_pitch_in_block)
|
||||
{
|
||||
unsigned short *castedDst = (unsigned short *)dst, *castedSrc = (unsigned short *)src;
|
||||
|
||||
for (unsigned row = 0; row < row_count; row++)
|
||||
for (unsigned row = 0; row < row_count * depth; row++)
|
||||
for (int j = 0; j < width_in_block; j++)
|
||||
{
|
||||
u16 tmp = castedSrc[row * src_pitch_in_block + j];
|
||||
@@ -97,10 +97,10 @@ struct texel_16b_format {
|
||||
*/
|
||||
struct texel_16bX4_format {
|
||||
template<size_t block_size>
|
||||
static void copy_mipmap_level(void *dst, void *src, size_t row_count, size_t width_in_block, size_t dst_pitch_in_block, size_t src_pitch_in_block)
|
||||
static void copy_mipmap_level(void *dst, void *src, u16 row_count, u16 width_in_block, u16 depth, size_t dst_pitch_in_block, size_t src_pitch_in_block)
|
||||
{
|
||||
unsigned short *casted_dst = (unsigned short *)dst, *casted_src = (unsigned short *)src;
|
||||
for (unsigned row = 0; row < row_count; row++)
|
||||
for (unsigned row = 0; row < row_count * depth; row++)
|
||||
for (int j = 0; j < width_in_block * 4; j++)
|
||||
{
|
||||
u16 tmp = casted_src[row * src_pitch_in_block * 4 + j];
|
||||
@@ -124,13 +124,13 @@ struct texel_16bX4_format {
|
||||
* mipmap level (to allow same code for packed/non packed texels)
|
||||
*/
|
||||
template <typename T, bool padded_row, size_t block_size_in_bytes, size_t block_edge_in_texel>
|
||||
std::vector<MipmapLevelInfo> copy_texture_data(void *dst, const void *src, size_t width_in_texel, size_t height_in_texel, size_t depth, size_t mipmap_count)
|
||||
std::vector<MipmapLevelInfo> copy_texture_data(void *dst, const void *src, u16 width_in_texel, u16 height_in_texel, u16 depth, u8 layer_count, u16 mipmap_count)
|
||||
{
|
||||
std::vector<MipmapLevelInfo> Result;
|
||||
size_t offsetInDst = 0, offsetInSrc = 0;
|
||||
size_t texture_height_in_block = (height_in_texel + block_edge_in_texel - 1) / block_edge_in_texel;
|
||||
size_t texture_width_in_block = (width_in_texel + block_edge_in_texel - 1) / block_edge_in_texel;
|
||||
for (unsigned depth_level = 0; depth_level < depth; depth_level++)
|
||||
for (unsigned layer = 0; layer < layer_count; layer++)
|
||||
{
|
||||
size_t miplevel_height_in_block = texture_height_in_block, miplevel_width_in_block = texture_width_in_block;
|
||||
for (unsigned mip_level = 0; mip_level < mipmap_count; mip_level++)
|
||||
@@ -141,18 +141,19 @@ std::vector<MipmapLevelInfo> copy_texture_data(void *dst, const void *src, size_
|
||||
currentMipmapLevelInfo.offset = offsetInDst;
|
||||
currentMipmapLevelInfo.height = miplevel_height_in_block * block_edge_in_texel;
|
||||
currentMipmapLevelInfo.width = miplevel_width_in_block * block_edge_in_texel;
|
||||
currentMipmapLevelInfo.depth = depth;
|
||||
currentMipmapLevelInfo.rowPitch = dst_pitch * block_size_in_bytes;
|
||||
Result.push_back(currentMipmapLevelInfo);
|
||||
|
||||
if (!padded_row)
|
||||
{
|
||||
T::template copy_mipmap_level<block_size_in_bytes>((char*)dst + offsetInDst, (char*)src + offsetInSrc, miplevel_height_in_block, miplevel_width_in_block, dst_pitch, miplevel_width_in_block);
|
||||
offsetInSrc += miplevel_height_in_block * miplevel_width_in_block * block_size_in_bytes;
|
||||
T::template copy_mipmap_level<block_size_in_bytes>((char*)dst + offsetInDst, (char*)src + offsetInSrc, miplevel_height_in_block, miplevel_width_in_block, depth, dst_pitch, miplevel_width_in_block);
|
||||
offsetInSrc += miplevel_height_in_block * miplevel_width_in_block * block_size_in_bytes * depth;
|
||||
}
|
||||
else
|
||||
{
|
||||
T::template copy_mipmap_level<block_size_in_bytes>((char*)dst + offsetInDst, (char*)src + offsetInSrc, miplevel_height_in_block, miplevel_width_in_block, dst_pitch, texture_width_in_block);
|
||||
offsetInSrc += miplevel_height_in_block * texture_width_in_block * block_size_in_bytes;
|
||||
T::template copy_mipmap_level<block_size_in_bytes>((char*)dst + offsetInDst, (char*)src + offsetInSrc, miplevel_height_in_block, miplevel_width_in_block, depth, dst_pitch, texture_width_in_block);
|
||||
offsetInSrc += miplevel_height_in_block * texture_width_in_block * block_size_in_bytes * depth;
|
||||
}
|
||||
offsetInDst += align(miplevel_height_in_block * dst_pitch * block_size_in_bytes, 512);
|
||||
miplevel_height_in_block = MAX2(miplevel_height_in_block / 2, 1);
|
||||
@@ -265,10 +266,28 @@ size_t get_placed_texture_storage_size(const rsx::texture &texture, size_t rowPi
|
||||
|
||||
std::vector<MipmapLevelInfo> upload_placed_texture(const rsx::texture &texture, size_t rowPitchAlignement, void* textureData)
|
||||
{
|
||||
size_t w = texture.width(), h = texture.height();
|
||||
size_t depth = texture.depth();
|
||||
if (depth == 0) depth = 1;
|
||||
if (texture.cubemap()) depth *= 6;
|
||||
u16 w = texture.width(), h = texture.height();
|
||||
u16 depth;
|
||||
u8 layer;
|
||||
|
||||
if (texture.dimension() == 1)
|
||||
{
|
||||
depth = 1;
|
||||
layer = 1;
|
||||
h = 1;
|
||||
}
|
||||
else if (texture.dimension() == 2)
|
||||
{
|
||||
depth = 1;
|
||||
layer = texture.cubemap() ? 6 : 1;
|
||||
}
|
||||
else if (texture.dimension() == 3)
|
||||
{
|
||||
depth = texture.depth();
|
||||
layer = 1;
|
||||
}
|
||||
else
|
||||
throw EXCEPTION("Unsupported texture dimension %d", texture.dimension());
|
||||
|
||||
int format = texture.format() & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN);
|
||||
|
||||
@@ -281,37 +300,37 @@ std::vector<MipmapLevelInfo> upload_placed_texture(const rsx::texture &texture,
|
||||
{
|
||||
case CELL_GCM_TEXTURE_A8R8G8B8:
|
||||
if (is_swizzled)
|
||||
return copy_texture_data<texel_rgba_swizzled, false, 4, 1>(textureData, pixels, w, h, depth, texture.mipmap());
|
||||
return copy_texture_data<texel_rgba_swizzled, false, 4, 1>(textureData, pixels, w, h, depth, layer, texture.mipmap());
|
||||
else
|
||||
return copy_texture_data<texel_rgba, true, 4, 1>(textureData, pixels, w, h, depth, texture.mipmap());
|
||||
return copy_texture_data<texel_rgba, true, 4, 1>(textureData, pixels, w, h, depth, layer, texture.mipmap());
|
||||
case CELL_GCM_TEXTURE_A1R5G5B5:
|
||||
case CELL_GCM_TEXTURE_A4R4G4B4:
|
||||
case CELL_GCM_TEXTURE_R5G6B5:
|
||||
if (is_swizzled)
|
||||
return copy_texture_data<texel_16b_swizzled, false, 2, 1>(textureData, pixels, w, h, depth, texture.mipmap());
|
||||
return copy_texture_data<texel_16b_swizzled, false, 2, 1>(textureData, pixels, w, h, depth, layer, texture.mipmap());
|
||||
else
|
||||
return copy_texture_data<texel_16b_format, true, 2, 1>(textureData, pixels, w, h, depth, texture.mipmap());
|
||||
return copy_texture_data<texel_16b_format, true, 2, 1>(textureData, pixels, w, h, depth, layer, texture.mipmap());
|
||||
case CELL_GCM_TEXTURE_W16_Z16_Y16_X16_FLOAT:
|
||||
return copy_texture_data<texel_16bX4_format, true, 8, 1>(textureData, pixels, w, h, depth, texture.mipmap());
|
||||
return copy_texture_data<texel_16bX4_format, true, 8, 1>(textureData, pixels, w, h, depth, layer, texture.mipmap());
|
||||
case CELL_GCM_TEXTURE_COMPRESSED_DXT1:
|
||||
if (is_swizzled)
|
||||
return copy_texture_data<texel_bc_format, false, 8, 4>(textureData, pixels, w, h, depth, texture.mipmap());
|
||||
return copy_texture_data<texel_bc_format, false, 8, 4>(textureData, pixels, w, h, depth, layer, texture.mipmap());
|
||||
else
|
||||
return copy_texture_data<texel_bc_format, true, 8, 4>(textureData, pixels, w, h, depth, texture.mipmap());
|
||||
return copy_texture_data<texel_bc_format, true, 8, 4>(textureData, pixels, w, h, depth, layer, texture.mipmap());
|
||||
case CELL_GCM_TEXTURE_COMPRESSED_DXT23:
|
||||
if (is_swizzled)
|
||||
return copy_texture_data<texel_bc_format, false, 16, 4>(textureData, pixels, w, h, depth, texture.mipmap());
|
||||
return copy_texture_data<texel_bc_format, false, 16, 4>(textureData, pixels, w, h, depth, layer, texture.mipmap());
|
||||
else
|
||||
return copy_texture_data<texel_bc_format, true, 16, 4>(textureData, pixels, w, h, depth, texture.mipmap());
|
||||
return copy_texture_data<texel_bc_format, true, 16, 4>(textureData, pixels, w, h, depth, layer, texture.mipmap());
|
||||
case CELL_GCM_TEXTURE_COMPRESSED_DXT45:
|
||||
if (is_swizzled)
|
||||
return copy_texture_data<texel_bc_format, false, 16, 4>(textureData, pixels, w, h, depth, texture.mipmap());
|
||||
return copy_texture_data<texel_bc_format, false, 16, 4>(textureData, pixels, w, h, depth, layer, texture.mipmap());
|
||||
else
|
||||
return copy_texture_data<texel_bc_format, true, 16, 4>(textureData, pixels, w, h, depth, texture.mipmap());
|
||||
return copy_texture_data<texel_bc_format, true, 16, 4>(textureData, pixels, w, h, depth, layer, texture.mipmap());
|
||||
case CELL_GCM_TEXTURE_B8:
|
||||
return copy_texture_data<texel_rgba, true, 1, 1>(textureData, pixels, w, h, depth, texture.mipmap());
|
||||
return copy_texture_data<texel_rgba, true, 1, 1>(textureData, pixels, w, h, depth, layer, texture.mipmap());
|
||||
default:
|
||||
return copy_texture_data<texel_rgba, true, 4, 1>(textureData, pixels, w, h, depth, texture.mipmap());
|
||||
return copy_texture_data<texel_rgba, true, 4, 1>(textureData, pixels, w, h, depth, layer, texture.mipmap());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,9 +5,10 @@
|
||||
struct MipmapLevelInfo
|
||||
{
|
||||
size_t offset;
|
||||
size_t width;
|
||||
size_t height;
|
||||
size_t rowPitch;
|
||||
u16 width;
|
||||
u16 height;
|
||||
u16 depth;
|
||||
u16 rowPitch;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -562,10 +562,10 @@ std::string VertexProgramDecompiler::Decompile()
|
||||
case RSX_SCA_OPCODE_MOV: SetDSTSca("$s"); break;
|
||||
case RSX_SCA_OPCODE_RCP: SetDSTSca("(1.0 / $s)"); break;
|
||||
case RSX_SCA_OPCODE_RCC: SetDSTSca("clamp(1.0 / $s, 5.42101e-20, 1.884467e19)"); break;
|
||||
case RSX_SCA_OPCODE_RSQ: SetDSTSca("(1.f / sqrt($s))"); break;
|
||||
case RSX_SCA_OPCODE_RSQ: SetDSTSca("rsq_legacy($s)"); break;
|
||||
case RSX_SCA_OPCODE_EXP: SetDSTSca("exp($s)"); break;
|
||||
case RSX_SCA_OPCODE_LOG: SetDSTSca("log($s)"); break;
|
||||
case RSX_SCA_OPCODE_LIT: SetDSTSca(getFloatTypeName(4) + "(1.0, $s.x, ($s.x > 0.0 ? exp($s.w * log2($s.y)) : 0.0), 1.0)"); break;
|
||||
case RSX_SCA_OPCODE_LIT: SetDSTSca("lit_legacy($s)"); break;
|
||||
case RSX_SCA_OPCODE_BRA:
|
||||
{
|
||||
AddCode("$if ($cond)");
|
||||
@@ -619,7 +619,7 @@ std::string VertexProgramDecompiler::Decompile()
|
||||
// works like BRI but shorter (RET o[1].x(TR);)
|
||||
AddCode("$ifcond return;");
|
||||
break;
|
||||
case RSX_SCA_OPCODE_LG2: SetDSTSca("log2($s)"); break;
|
||||
case RSX_SCA_OPCODE_LG2: SetDSTSca("log2_legacy($s)"); break;
|
||||
case RSX_SCA_OPCODE_EX2: SetDSTSca("exp2($s)"); break;
|
||||
case RSX_SCA_OPCODE_SIN: SetDSTSca("sin($s)"); break;
|
||||
case RSX_SCA_OPCODE_COS: SetDSTSca("cos($s)"); break;
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
#include "stdafx.h"
|
||||
#include "surface_store.h"
|
||||
|
||||
namespace rsx
|
||||
{
|
||||
namespace utility
|
||||
{
|
||||
std::vector<u8> get_rtt_indexes(surface_target color_target)
|
||||
{
|
||||
switch (color_target)
|
||||
{
|
||||
case surface_target::none: return{};
|
||||
case surface_target::surface_a: return{ 0 };
|
||||
case surface_target::surface_b: return{ 1 };
|
||||
case surface_target::surfaces_a_b: return{ 0, 1 };
|
||||
case surface_target::surfaces_a_b_c: return{ 0, 1, 2 };
|
||||
case surface_target::surfaces_a_b_c_d: return{ 0, 1, 2, 3 };
|
||||
}
|
||||
throw EXCEPTION("Wrong color_target");
|
||||
}
|
||||
|
||||
size_t get_aligned_pitch(surface_color_format format, u32 width)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case surface_color_format::b8: return align(width, 256);
|
||||
case surface_color_format::g8b8:
|
||||
case surface_color_format::x1r5g5b5_o1r5g5b5:
|
||||
case surface_color_format::x1r5g5b5_z1r5g5b5:
|
||||
case surface_color_format::r5g6b5: return align(width * 2, 256);
|
||||
case surface_color_format::a8b8g8r8:
|
||||
case surface_color_format::x8b8g8r8_o8b8g8r8:
|
||||
case surface_color_format::x8b8g8r8_z8b8g8r8:
|
||||
case surface_color_format::x8r8g8b8_o8r8g8b8:
|
||||
case surface_color_format::x8r8g8b8_z8r8g8b8:
|
||||
case surface_color_format::x32:
|
||||
case surface_color_format::a8r8g8b8: return align(width * 4, 256);
|
||||
case surface_color_format::w16z16y16x16: return align(width * 8, 256);
|
||||
case surface_color_format::w32z32y32x32: return align(width * 16, 256);
|
||||
}
|
||||
throw EXCEPTION("Unknow color surface format");
|
||||
}
|
||||
|
||||
size_t get_packed_pitch(surface_color_format format, u32 width)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case surface_color_format::b8: return width;
|
||||
case surface_color_format::g8b8:
|
||||
case surface_color_format::x1r5g5b5_o1r5g5b5:
|
||||
case surface_color_format::x1r5g5b5_z1r5g5b5:
|
||||
case surface_color_format::r5g6b5: return width * 2;
|
||||
case surface_color_format::a8b8g8r8:
|
||||
case surface_color_format::x8b8g8r8_o8b8g8r8:
|
||||
case surface_color_format::x8b8g8r8_z8b8g8r8:
|
||||
case surface_color_format::x8r8g8b8_o8r8g8b8:
|
||||
case surface_color_format::x8r8g8b8_z8r8g8b8:
|
||||
case surface_color_format::x32:
|
||||
case surface_color_format::a8r8g8b8: return width * 4;
|
||||
case surface_color_format::w16z16y16x16: return width * 8;
|
||||
case surface_color_format::w32z32y32x32: return width * 16;
|
||||
}
|
||||
throw EXCEPTION("Unknow color surface format");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,348 @@
|
||||
#pragma once
|
||||
|
||||
#include <gsl.h>
|
||||
#include "../GCM.h"
|
||||
|
||||
namespace rsx
|
||||
{
|
||||
namespace utility
|
||||
{
|
||||
std::vector<u8> get_rtt_indexes(surface_target color_target);
|
||||
size_t get_aligned_pitch(surface_color_format format, u32 width);
|
||||
size_t get_packed_pitch(surface_color_format format, u32 width);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper for surface (ie color and depth stencil render target) management.
|
||||
* It handles surface creation and storage. Backend should only retrieve pointer to surface.
|
||||
* It provides 2 methods get_texture_from_*_if_applicable that should be used when an app
|
||||
* wants to sample a previous surface.
|
||||
* Please note that the backend is still responsible for creating framebuffer/descriptors
|
||||
* and need to inform surface_store everytime surface format/size/addresses change.
|
||||
*
|
||||
* Since it's a template it requires a trait with the followings:
|
||||
* - type surface_storage_type which is a structure containing texture.
|
||||
* - type surface_type which is a pointer to storage_type or a reference.
|
||||
* - type command_list_type that can be void for backend without command list
|
||||
* - type download_buffer_object used by issue_download_command and map_downloaded_buffer functions to handle sync
|
||||
*
|
||||
* - a member function static surface_type(const surface_storage_type&) that returns underlying surface pointer from a storage type.
|
||||
* - 2 member functions static surface_storage_type create_new_surface(u32 address, Surface_color_format/Surface_depth_format format, size_t width, size_t height,...)
|
||||
* used to create a new surface_storage_type holding surface from passed parameters.
|
||||
* - a member function static prepare_rtt_for_drawing(command_list, surface_type) that makes a sampleable surface a color render target one.
|
||||
* - a member function static prepare_rtt_for_drawing(command_list, surface_type) that makes a render target surface a sampleable one.
|
||||
* - a member function static prepare_ds_for_drawing that does the same for depth stencil surface.
|
||||
* - a member function static prepare_ds_for_sampling that does the same for depth stencil surface.
|
||||
* - a member function static bool rtt_has_format_width_height(const surface_storage_type&, Surface_color_format surface_color_format, size_t width, size_t height)
|
||||
* that checks if the given surface has the given format and size
|
||||
* - a member function static bool ds_has_format_width_height that does the same for ds
|
||||
* - a member function static download_buffer_object issue_download_command(surface_type, Surface_color_format color_format, size_t width, size_t height,...)
|
||||
* that generates command to download the given surface to some mappable buffer.
|
||||
* - a member function static issue_depth_download_command that does the same for depth surface
|
||||
* - a member function static issue_stencil_download_command that does the same for stencil surface
|
||||
* - a member function gsl::span<const gsl::byte> map_downloaded_buffer(download_buffer_object, ...) that maps a download_buffer_object
|
||||
* - a member function static unmap_downloaded_buffer that unmaps it.
|
||||
*/
|
||||
template<typename Traits>
|
||||
struct surface_store
|
||||
{
|
||||
template<typename T, typename U>
|
||||
void copy_pitched_src_to_dst(gsl::span<T> dest, gsl::span<const U> src, size_t src_pitch_in_bytes, size_t width, size_t height)
|
||||
{
|
||||
for (int row = 0; row < height; row++)
|
||||
{
|
||||
for (unsigned col = 0; col < width; col++)
|
||||
dest[col] = src[col];
|
||||
src = src.subspan(src_pitch_in_bytes / sizeof(U));
|
||||
dest = dest.subspan(width);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
using surface_storage_type = typename Traits::surface_storage_type;
|
||||
using surface_type = typename Traits::surface_type;
|
||||
using command_list_type = typename Traits::command_list_type;
|
||||
using download_buffer_object = typename Traits::download_buffer_object;
|
||||
|
||||
std::unordered_map<u32, surface_storage_type> m_render_targets_storage = {};
|
||||
std::unordered_map<u32, surface_storage_type> m_depth_stencil_storage = {};
|
||||
|
||||
public:
|
||||
std::array<std::tuple<u32, surface_type>, 4> m_bound_render_targets = {};
|
||||
std::tuple<u32, surface_type> m_bound_depth_stencil = {};
|
||||
|
||||
std::list<surface_storage_type> invalidated_resources;
|
||||
|
||||
surface_store() = default;
|
||||
~surface_store() = default;
|
||||
surface_store(const surface_store&) = delete;
|
||||
private:
|
||||
/**
|
||||
* If render target already exists at address, issue state change operation on cmdList.
|
||||
* Otherwise create one with width, height, clearColor info.
|
||||
* returns the corresponding render target resource.
|
||||
*/
|
||||
template <typename ...Args>
|
||||
gsl::not_null<surface_type> bind_address_as_render_targets(
|
||||
command_list_type command_list,
|
||||
u32 address,
|
||||
surface_color_format color_format, size_t width, size_t height,
|
||||
Args&&... extra_params)
|
||||
{
|
||||
auto It = m_render_targets_storage.find(address);
|
||||
// TODO: Fix corner cases
|
||||
// This doesn't take overlapping surface(s) into account.
|
||||
// Invalidated surface(s) should also copy their content to the new resources.
|
||||
if (It != m_render_targets_storage.end())
|
||||
{
|
||||
surface_storage_type &rtt = It->second;
|
||||
if (Traits::rtt_has_format_width_height(rtt, color_format, width, height))
|
||||
{
|
||||
Traits::prepare_rtt_for_drawing(command_list, Traits::get(rtt));
|
||||
return Traits::get(rtt);
|
||||
}
|
||||
invalidated_resources.push_back(std::move(rtt));
|
||||
m_render_targets_storage.erase(address);
|
||||
}
|
||||
|
||||
m_render_targets_storage[address] = Traits::create_new_surface(address, color_format, width, height, std::forward<Args>(extra_params)...);
|
||||
return Traits::get(m_render_targets_storage[address]);
|
||||
}
|
||||
|
||||
template <typename ...Args>
|
||||
gsl::not_null<surface_type> bind_address_as_depth_stencil(
|
||||
command_list_type command_list,
|
||||
u32 address,
|
||||
surface_depth_format depth_format, size_t width, size_t height,
|
||||
Args&&... extra_params)
|
||||
{
|
||||
auto It = m_depth_stencil_storage.find(address);
|
||||
if (It != m_depth_stencil_storage.end())
|
||||
{
|
||||
surface_storage_type &ds = It->second;
|
||||
if (Traits::ds_has_format_width_height(ds, depth_format, width, height))
|
||||
{
|
||||
Traits::prepare_ds_for_drawing(command_list, Traits::get(ds));
|
||||
return Traits::get(ds);
|
||||
}
|
||||
invalidated_resources.push_back(std::move(ds));
|
||||
m_depth_stencil_storage.erase(address);
|
||||
}
|
||||
|
||||
m_depth_stencil_storage[address] = Traits::create_new_surface(address, depth_format, width, height, std::forward<Args>(extra_params)...);
|
||||
return Traits::get(m_depth_stencil_storage[address]);
|
||||
}
|
||||
public:
|
||||
/**
|
||||
* Update bound color and depth surface.
|
||||
* Must be called everytime surface format, clip, or addresses changes.
|
||||
*/
|
||||
template <typename ...Args>
|
||||
void prepare_render_target(
|
||||
command_list_type command_list,
|
||||
u32 set_surface_format_reg,
|
||||
u32 clip_horizontal_reg, u32 clip_vertical_reg,
|
||||
surface_target set_surface_target,
|
||||
const std::array<u32, 4> &surface_addresses, u32 address_z,
|
||||
Args&&... extra_params)
|
||||
{
|
||||
u32 clip_width = clip_horizontal_reg >> 16;
|
||||
u32 clip_height = clip_vertical_reg >> 16;
|
||||
u32 clip_x = clip_horizontal_reg;
|
||||
u32 clip_y = clip_vertical_reg;
|
||||
|
||||
surface_color_format color_format = to_surface_color_format(set_surface_format_reg & 0x1f);
|
||||
surface_depth_format depth_format = to_surface_depth_format((set_surface_format_reg >> 5) & 0x7);
|
||||
|
||||
// Make previous RTTs sampleable
|
||||
for (std::tuple<u32, surface_type> &rtt : m_bound_render_targets)
|
||||
{
|
||||
if (std::get<1>(rtt) != nullptr)
|
||||
Traits::prepare_rtt_for_sampling(command_list, std::get<1>(rtt));
|
||||
rtt = std::make_tuple(0, nullptr);
|
||||
}
|
||||
|
||||
// Create/Reuse requested rtts
|
||||
for (u8 surface_index : utility::get_rtt_indexes(set_surface_target))
|
||||
{
|
||||
if (surface_addresses[surface_index] == 0)
|
||||
continue;
|
||||
|
||||
m_bound_render_targets[surface_index] = std::make_tuple(surface_addresses[surface_index],
|
||||
bind_address_as_render_targets(command_list, surface_addresses[surface_index], color_format, clip_width, clip_height, std::forward<Args>(extra_params)...));
|
||||
}
|
||||
|
||||
// Same for depth buffer
|
||||
if (std::get<1>(m_bound_depth_stencil) != nullptr)
|
||||
Traits::prepare_ds_for_sampling(command_list, std::get<1>(m_bound_depth_stencil));
|
||||
m_bound_depth_stencil = std::make_tuple(0, nullptr);
|
||||
if (!address_z)
|
||||
return;
|
||||
m_bound_depth_stencil = std::make_tuple(address_z,
|
||||
bind_address_as_depth_stencil(command_list, address_z, depth_format, clip_width, clip_height, std::forward<Args>(extra_params)...));
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for given address in stored color surface and returns it if size/format match.
|
||||
* Return an empty surface_type otherwise.
|
||||
*/
|
||||
surface_type get_texture_from_render_target_if_applicable(u32 address)
|
||||
{
|
||||
// TODO: Handle texture that overlaps one (or several) surface.
|
||||
// Handle texture conversion
|
||||
// FIXME: Disgaea 3 loading screen seems to use a subset of a surface. It's not properly handled here.
|
||||
// Note: not const because conversions/resolve/... can happen
|
||||
auto It = m_render_targets_storage.find(address);
|
||||
if (It != m_render_targets_storage.end())
|
||||
return Traits::get(It->second);
|
||||
return surface_type();
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for given address in stored depth stencil surface and returns it if size/format match.
|
||||
* Return an empty surface_type otherwise.
|
||||
*/
|
||||
surface_type get_texture_from_depth_stencil_if_applicable(u32 address)
|
||||
{
|
||||
// TODO: Same as above although there wasn't any game using corner case for DS yet.
|
||||
auto It = m_depth_stencil_storage.find(address);
|
||||
if (It != m_depth_stencil_storage.end())
|
||||
return Traits::get(It->second);
|
||||
return surface_type();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get bound color surface raw data.
|
||||
*/
|
||||
template <typename... Args>
|
||||
std::array<std::vector<gsl::byte>, 4> get_render_targets_data(
|
||||
surface_color_format color_format, size_t width, size_t height,
|
||||
Args&& ...args
|
||||
)
|
||||
{
|
||||
std::array<download_buffer_object, 4> download_data = {};
|
||||
|
||||
// Issue download commands
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
if (std::get<0>(m_bound_render_targets[i]) == 0)
|
||||
continue;
|
||||
|
||||
surface_type surface_resource = std::get<1>(m_bound_render_targets[i]);
|
||||
download_data[i] = std::move(
|
||||
Traits::issue_download_command(surface_resource, color_format, width, height, std::forward<Args&&>(args)...)
|
||||
);
|
||||
}
|
||||
|
||||
std::array<std::vector<gsl::byte>, 4> result = {};
|
||||
|
||||
// Sync and copy data
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
if (std::get<0>(m_bound_render_targets[i]) == 0)
|
||||
continue;
|
||||
|
||||
gsl::span<const gsl::byte> raw_src = Traits::map_downloaded_buffer(download_data[i], std::forward<Args&&>(args)...);
|
||||
|
||||
size_t src_pitch = utility::get_aligned_pitch(color_format, gsl::narrow<u32>(width));
|
||||
size_t dst_pitch = utility::get_packed_pitch(color_format, gsl::narrow<u32>(width));
|
||||
|
||||
result[i].resize(dst_pitch * height);
|
||||
|
||||
// Note: MSVC + GSL doesn't support span<byte> -> span<T> for non const span atm
|
||||
// thus manual conversion
|
||||
switch (color_format)
|
||||
{
|
||||
case surface_color_format::a8b8g8r8:
|
||||
case surface_color_format::x8b8g8r8_o8b8g8r8:
|
||||
case surface_color_format::x8b8g8r8_z8b8g8r8:
|
||||
case surface_color_format::a8r8g8b8:
|
||||
case surface_color_format::x8r8g8b8_o8r8g8b8:
|
||||
case surface_color_format::x8r8g8b8_z8r8g8b8:
|
||||
case surface_color_format::x32:
|
||||
{
|
||||
gsl::span<be_t<u32>> dst_span{ (be_t<u32>*)result[i].data(), gsl::narrow<int>(dst_pitch * width / sizeof(be_t<u32>)) };
|
||||
copy_pitched_src_to_dst(dst_span, gsl::as_span<const u32>(raw_src), src_pitch, width, height);
|
||||
break;
|
||||
}
|
||||
case surface_color_format::b8:
|
||||
{
|
||||
gsl::span<u8> dst_span{ (u8*)result[i].data(), gsl::narrow<int>(dst_pitch * width / sizeof(u8)) };
|
||||
copy_pitched_src_to_dst(dst_span, gsl::as_span<const u8>(raw_src), src_pitch, width, height);
|
||||
break;
|
||||
}
|
||||
case surface_color_format::g8b8:
|
||||
case surface_color_format::r5g6b5:
|
||||
case surface_color_format::x1r5g5b5_o1r5g5b5:
|
||||
case surface_color_format::x1r5g5b5_z1r5g5b5:
|
||||
{
|
||||
gsl::span<be_t<u16>> dst_span{ (be_t<u16>*)result[i].data(), gsl::narrow<int>(dst_pitch * width / sizeof(be_t<u16>)) };
|
||||
copy_pitched_src_to_dst(dst_span, gsl::as_span<const u16>(raw_src), src_pitch, width, height);
|
||||
break;
|
||||
}
|
||||
// Note : may require some big endian swap
|
||||
case surface_color_format::w32z32y32x32:
|
||||
{
|
||||
gsl::span<u128> dst_span{ (u128*)result[i].data(), gsl::narrow<int>(dst_pitch * width / sizeof(u128)) };
|
||||
copy_pitched_src_to_dst(dst_span, gsl::as_span<const u128>(raw_src), src_pitch, width, height);
|
||||
break;
|
||||
}
|
||||
case surface_color_format::w16z16y16x16:
|
||||
{
|
||||
gsl::span<u64> dst_span{ (u64*)result[i].data(), gsl::narrow<int>(dst_pitch * width / sizeof(u64)) };
|
||||
copy_pitched_src_to_dst(dst_span, gsl::as_span<const u64>(raw_src), src_pitch, width, height);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
Traits::unmap_downloaded_buffer(download_data[i], std::forward<Args&&>(args)...);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get bound color surface raw data.
|
||||
*/
|
||||
template <typename... Args>
|
||||
std::array<std::vector<gsl::byte>, 2> get_depth_stencil_data(
|
||||
surface_depth_format depth_format, size_t width, size_t height,
|
||||
Args&& ...args
|
||||
)
|
||||
{
|
||||
std::array<std::vector<gsl::byte>, 2> result = {};
|
||||
if (std::get<0>(m_bound_depth_stencil) == 0)
|
||||
return result;
|
||||
size_t row_pitch = align(width * 4, 256);
|
||||
|
||||
download_buffer_object stencil_data = {};
|
||||
download_buffer_object depth_data = Traits::issue_depth_download_command(std::get<1>(m_bound_depth_stencil), depth_format, width, height, std::forward<Args&&>(args)...);
|
||||
if (depth_format == surface_depth_format::z24s8)
|
||||
stencil_data = std::move(Traits::issue_stencil_download_command(std::get<1>(m_bound_depth_stencil), width, height, std::forward<Args&&>(args)...));
|
||||
|
||||
gsl::span<const gsl::byte> depth_buffer_raw_src = Traits::map_downloaded_buffer(depth_data, std::forward<Args&&>(args)...);
|
||||
if (depth_format == surface_depth_format::z16)
|
||||
{
|
||||
result[0].resize(width * height * 2);
|
||||
gsl::span<u16> dest{ (u16*)result[0].data(), gsl::narrow<int>(width * height) };
|
||||
copy_pitched_src_to_dst(dest, gsl::as_span<const u16>(depth_buffer_raw_src), row_pitch, width, height);
|
||||
}
|
||||
if (depth_format == surface_depth_format::z24s8)
|
||||
{
|
||||
result[0].resize(width * height * 4);
|
||||
gsl::span<u32> dest{ (u32*)result[0].data(), gsl::narrow<int>(width * height) };
|
||||
copy_pitched_src_to_dst(dest, gsl::as_span<const u32>(depth_buffer_raw_src), row_pitch, width, height);
|
||||
}
|
||||
Traits::unmap_downloaded_buffer(depth_data, std::forward<Args&&>(args)...);
|
||||
|
||||
if (depth_format == surface_depth_format::z16)
|
||||
return result;
|
||||
|
||||
gsl::span<const gsl::byte> stencil_buffer_raw_src = Traits::map_downloaded_buffer(stencil_data, std::forward<Args&&>(args)...);
|
||||
result[1].resize(width * height);
|
||||
gsl::span<u8> dest{ (u8*)result[1].data(), gsl::narrow<int>(width * height) };
|
||||
copy_pitched_src_to_dst(dest, gsl::as_span<const u8>(stencil_buffer_raw_src), align(width, 256), width, height);
|
||||
Traits::unmap_downloaded_buffer(stencil_data, std::forward<Args&&>(args)...);
|
||||
return result;
|
||||
}
|
||||
};
|
||||
}
|
||||
+168
-138
@@ -8,19 +8,75 @@
|
||||
#include "D3D12Formats.h"
|
||||
#include "../rsx_methods.h"
|
||||
|
||||
|
||||
std::vector<D3D12_VERTEX_BUFFER_VIEW> D3D12GSRender::upload_vertex_attributes(const std::vector<std::pair<u32, u32> > &vertex_ranges)
|
||||
namespace
|
||||
{
|
||||
std::vector<D3D12_VERTEX_BUFFER_VIEW> vertex_buffer_views;
|
||||
UINT get_component_mapping_from_vector_size(u8 size)
|
||||
{
|
||||
switch (size)
|
||||
{
|
||||
case 1:
|
||||
return D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING(
|
||||
D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_0,
|
||||
D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_0,
|
||||
D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_0,
|
||||
D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_1);
|
||||
case 2:
|
||||
return D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING(
|
||||
D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_0,
|
||||
D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_1,
|
||||
D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_0,
|
||||
D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_1);
|
||||
case 3:
|
||||
return D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING(
|
||||
D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_0,
|
||||
D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_1,
|
||||
D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_2,
|
||||
D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_1);
|
||||
case 4:
|
||||
return D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
|
||||
}
|
||||
throw EXCEPTION("Wrong vector size %d", size);
|
||||
}
|
||||
|
||||
m_IASet.clear();
|
||||
size_t input_slot = 0;
|
||||
u32 get_vertex_count(const std::vector<std::pair<u32, u32> > first_count_commands)
|
||||
{
|
||||
u32 vertex_count = 0;
|
||||
for (const auto &pair : first_count_commands)
|
||||
vertex_count += pair.second;
|
||||
return vertex_count;
|
||||
}
|
||||
|
||||
size_t vertex_count = 0;
|
||||
D3D12_SHADER_RESOURCE_VIEW_DESC get_vertex_attribute_srv(const rsx::data_array_format_info &info, UINT64 offset_in_vertex_buffers_buffer, UINT buffer_size)
|
||||
{
|
||||
u32 element_size = rsx::get_vertex_type_size_on_host(info.type, info.size);
|
||||
D3D12_SHADER_RESOURCE_VIEW_DESC vertex_buffer_view = {
|
||||
get_vertex_attribute_format(info.type, info.size),
|
||||
D3D12_SRV_DIMENSION_BUFFER,
|
||||
get_component_mapping_from_vector_size(info.size)
|
||||
};
|
||||
vertex_buffer_view.Buffer.FirstElement = offset_in_vertex_buffers_buffer / element_size;
|
||||
vertex_buffer_view.Buffer.NumElements = buffer_size / element_size;
|
||||
return vertex_buffer_view;
|
||||
}
|
||||
|
||||
for (const auto &pair : vertex_ranges)
|
||||
vertex_count += pair.second;
|
||||
template<int N>
|
||||
UINT64 get_next_multiple_of(UINT64 val)
|
||||
{
|
||||
UINT64 divided_val = (val + N - 1) / N;
|
||||
return divided_val * N;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::vector<D3D12_SHADER_RESOURCE_VIEW_DESC> D3D12GSRender::upload_vertex_attributes(
|
||||
const std::vector<std::pair<u32, u32> > &vertex_ranges,
|
||||
gsl::not_null<ID3D12GraphicsCommandList*> command_list)
|
||||
{
|
||||
std::vector<D3D12_SHADER_RESOURCE_VIEW_DESC> vertex_buffer_views;
|
||||
command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_vertex_buffer_data.Get(), D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER, D3D12_RESOURCE_STATE_COPY_DEST));
|
||||
|
||||
u32 vertex_count = get_vertex_count(vertex_ranges);
|
||||
size_t offset_in_vertex_buffers_buffer = 0;
|
||||
u32 input_mask = rsx::method_registers[NV4097_SET_VERTEX_ATTRIB_INPUT_MASK];
|
||||
|
||||
for (int index = 0; index < rsx::limits::vertex_count; ++index)
|
||||
@@ -35,8 +91,7 @@ std::vector<D3D12_VERTEX_BUFFER_VIEW> D3D12GSRender::upload_vertex_attributes(co
|
||||
const rsx::data_array_format_info &info = vertex_arrays_info[index];
|
||||
|
||||
u32 element_size = rsx::get_vertex_type_size_on_host(info.type, info.size);
|
||||
|
||||
size_t buffer_size = element_size * vertex_count;
|
||||
UINT buffer_size = element_size * vertex_count;
|
||||
size_t heap_offset = m_buffer_data.alloc<D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT>(buffer_size);
|
||||
|
||||
void *mapped_buffer = m_buffer_data.map<void>(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size));
|
||||
@@ -47,64 +102,104 @@ std::vector<D3D12_VERTEX_BUFFER_VIEW> D3D12GSRender::upload_vertex_attributes(co
|
||||
}
|
||||
m_buffer_data.unmap(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size));
|
||||
|
||||
D3D12_VERTEX_BUFFER_VIEW vertex_buffer_view =
|
||||
{
|
||||
m_buffer_data.get_heap()->GetGPUVirtualAddress() + heap_offset,
|
||||
(UINT)buffer_size,
|
||||
(UINT)element_size
|
||||
};
|
||||
vertex_buffer_views.push_back(vertex_buffer_view);
|
||||
command_list->CopyBufferRegion(m_vertex_buffer_data.Get(), offset_in_vertex_buffers_buffer, m_buffer_data.get_heap(), heap_offset, buffer_size);
|
||||
|
||||
m_timers.m_buffer_upload_size += buffer_size;
|
||||
vertex_buffer_views.emplace_back(get_vertex_attribute_srv(info, offset_in_vertex_buffers_buffer, buffer_size));
|
||||
offset_in_vertex_buffers_buffer = get_next_multiple_of<48>(offset_in_vertex_buffers_buffer + buffer_size); // 48 is multiple of 2, 4, 6, 8, 12, 16
|
||||
|
||||
m_timers.buffer_upload_size += buffer_size;
|
||||
|
||||
D3D12_INPUT_ELEMENT_DESC IAElement = {};
|
||||
IAElement.SemanticName = "TEXCOORD";
|
||||
IAElement.SemanticIndex = (UINT)index;
|
||||
IAElement.InputSlot = (UINT)input_slot++;
|
||||
IAElement.Format = get_vertex_attribute_format(info.type, info.size);
|
||||
IAElement.AlignedByteOffset = 0;
|
||||
IAElement.InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA;
|
||||
IAElement.InstanceDataStepRate = 0;
|
||||
m_IASet.push_back(IAElement);
|
||||
}
|
||||
else if (register_vertex_info[index].size > 0)
|
||||
{
|
||||
// In register vertex attribute
|
||||
const rsx::data_array_format_info &info = register_vertex_info[index];
|
||||
|
||||
const std::vector<u8> &data = register_vertex_data[index];
|
||||
|
||||
u32 element_size = rsx::get_vertex_type_size_on_host(info.type, info.size);
|
||||
|
||||
size_t buffer_size = data.size();
|
||||
UINT buffer_size = gsl::narrow<UINT>(data.size());
|
||||
size_t heap_offset = m_buffer_data.alloc<D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT>(buffer_size);
|
||||
|
||||
void *mapped_buffer = m_buffer_data.map<void>(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size));
|
||||
memcpy(mapped_buffer, data.data(), data.size());
|
||||
m_buffer_data.unmap(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size));
|
||||
|
||||
D3D12_VERTEX_BUFFER_VIEW vertex_buffer_view = {
|
||||
m_buffer_data.get_heap()->GetGPUVirtualAddress() + heap_offset,
|
||||
(UINT)buffer_size,
|
||||
(UINT)element_size
|
||||
};
|
||||
vertex_buffer_views.push_back(vertex_buffer_view);
|
||||
command_list->CopyBufferRegion(m_vertex_buffer_data.Get(), offset_in_vertex_buffers_buffer, m_buffer_data.get_heap(), heap_offset, buffer_size);
|
||||
|
||||
D3D12_INPUT_ELEMENT_DESC IAElement = {};
|
||||
IAElement.SemanticName = "TEXCOORD";
|
||||
IAElement.SemanticIndex = (UINT)index;
|
||||
IAElement.InputSlot = (UINT)input_slot++;
|
||||
IAElement.Format = get_vertex_attribute_format(info.type, info.size);
|
||||
IAElement.AlignedByteOffset = 0;
|
||||
IAElement.InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA;
|
||||
IAElement.InstanceDataStepRate = 1;
|
||||
m_IASet.push_back(IAElement);
|
||||
vertex_buffer_views.emplace_back(get_vertex_attribute_srv(info, offset_in_vertex_buffers_buffer, buffer_size));
|
||||
offset_in_vertex_buffers_buffer = get_next_multiple_of<48>(offset_in_vertex_buffers_buffer + buffer_size); // 48 is multiple of 2, 4, 6, 8, 12, 16
|
||||
}
|
||||
}
|
||||
|
||||
command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_vertex_buffer_data.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER));
|
||||
return vertex_buffer_views;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
std::tuple<std::vector<D3D12_SHADER_RESOURCE_VIEW_DESC>, size_t> upload_inlined_vertex_array(
|
||||
gsl::span<const rsx::data_array_format_info, 16> vertex_attribute_infos,
|
||||
gsl::span<const gsl::byte> inlined_array_raw_data,
|
||||
data_heap& ring_buffer_data,
|
||||
ID3D12Resource* vertex_buffer_placement,
|
||||
ID3D12GraphicsCommandList* command_list
|
||||
)
|
||||
{
|
||||
// We can't rely on vertex_attribute_infos strides here so compute it
|
||||
// assuming all attributes are packed
|
||||
u32 stride = 0;
|
||||
for (const auto &info : vertex_attribute_infos)
|
||||
{
|
||||
if (!info.size) // disabled
|
||||
continue;
|
||||
|
||||
stride += rsx::get_vertex_type_size_on_host(info.type, info.size);
|
||||
}
|
||||
|
||||
u32 element_count = gsl::narrow<u32>(inlined_array_raw_data.size_bytes()) / stride;
|
||||
std::vector<D3D12_SHADER_RESOURCE_VIEW_DESC> result;
|
||||
|
||||
UINT64 vertex_buffer_offset = 0;
|
||||
for (const auto &info : vertex_attribute_infos)
|
||||
{
|
||||
if (!info.size) // disabled
|
||||
continue;
|
||||
|
||||
u32 element_size = rsx::get_vertex_type_size_on_host(info.type, info.size);
|
||||
UINT buffer_size = element_size * element_count;
|
||||
size_t heap_offset = ring_buffer_data.alloc<D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT>(buffer_size);
|
||||
|
||||
void *mapped_buffer = ring_buffer_data.map<void>(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size));
|
||||
gsl::span<gsl::byte> dst = { (gsl::byte*)mapped_buffer, buffer_size };
|
||||
|
||||
for (u32 i = 0; i < element_count; i++)
|
||||
{
|
||||
auto subdst = dst.subspan(i * element_size, element_size);
|
||||
auto subsrc = inlined_array_raw_data.subspan(i * stride, element_size);
|
||||
if (info.type == rsx::vertex_base_type::ub && info.size == 4)
|
||||
{
|
||||
subdst[0] = subsrc[3];
|
||||
subdst[1] = subsrc[2];
|
||||
subdst[2] = subsrc[1];
|
||||
subdst[3] = subsrc[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
std::copy(subsrc.begin(), subsrc.end(), subdst.begin());
|
||||
}
|
||||
}
|
||||
|
||||
ring_buffer_data.unmap(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size));
|
||||
|
||||
command_list->CopyBufferRegion(vertex_buffer_placement, vertex_buffer_offset, ring_buffer_data.get_heap(), heap_offset, buffer_size);
|
||||
|
||||
result.emplace_back(get_vertex_attribute_srv(info, vertex_buffer_offset, buffer_size));
|
||||
vertex_buffer_offset = get_next_multiple_of<48>(vertex_buffer_offset + buffer_size); // 48 is multiple of 2, 4, 6, 8, 12, 16
|
||||
}
|
||||
|
||||
return std::make_tuple(result, element_count);
|
||||
}
|
||||
}
|
||||
|
||||
void D3D12GSRender::upload_and_bind_scale_offset_matrix(size_t descriptorIndex)
|
||||
{
|
||||
size_t heap_offset = m_buffer_data.alloc<D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT>(256);
|
||||
@@ -114,25 +209,10 @@ void D3D12GSRender::upload_and_bind_scale_offset_matrix(size_t descriptorIndex)
|
||||
void *mapped_buffer = m_buffer_data.map<void>(CD3DX12_RANGE(heap_offset, heap_offset + 256));
|
||||
fill_scale_offset_data(mapped_buffer);
|
||||
int is_alpha_tested = !!(rsx::method_registers[NV4097_SET_ALPHA_TEST_ENABLE]);
|
||||
float alpha_ref = (float&)rsx::method_registers[NV4097_SET_ALPHA_REF];
|
||||
u8 alpha_ref_raw = (u8)(rsx::method_registers[NV4097_SET_ALPHA_REF] & 0xFF);
|
||||
float alpha_ref = alpha_ref_raw / 255.f;
|
||||
memcpy((char*)mapped_buffer + 16 * sizeof(float), &is_alpha_tested, sizeof(int));
|
||||
memcpy((char*)mapped_buffer + 17 * sizeof(float), &alpha_ref, sizeof(float));
|
||||
|
||||
size_t tex_idx = 0;
|
||||
for (u32 i = 0; i < rsx::limits::textures_count; ++i)
|
||||
{
|
||||
if (!textures[i].enabled())
|
||||
{
|
||||
int is_unorm = false;
|
||||
memcpy((char*)mapped_buffer + (18 + tex_idx++) * sizeof(int), &is_unorm, sizeof(int));
|
||||
continue;
|
||||
}
|
||||
size_t w = textures[i].width(), h = textures[i].height();
|
||||
// if (!w || !h) continue;
|
||||
|
||||
int is_unorm = (textures[i].format() & CELL_GCM_TEXTURE_UN);
|
||||
memcpy((char*)mapped_buffer + (18 + tex_idx++) * sizeof(int), &is_unorm, sizeof(int));
|
||||
}
|
||||
m_buffer_data.unmap(CD3DX12_RANGE(heap_offset, heap_offset + 256));
|
||||
|
||||
D3D12_CONSTANT_BUFFER_VIEW_DESC constant_buffer_view_desc = {
|
||||
@@ -141,7 +221,7 @@ void D3D12GSRender::upload_and_bind_scale_offset_matrix(size_t descriptorIndex)
|
||||
};
|
||||
m_device->CreateConstantBufferView(&constant_buffer_view_desc,
|
||||
CD3DX12_CPU_DESCRIPTOR_HANDLE(get_current_resource_storage().descriptors_heap->GetCPUDescriptorHandleForHeapStart())
|
||||
.Offset((INT)descriptorIndex, g_descriptor_stride_srv_cbv_uav));
|
||||
.Offset((INT)descriptorIndex, m_descriptor_stride_srv_cbv_uav));
|
||||
}
|
||||
|
||||
void D3D12GSRender::upload_and_bind_vertex_shader_constants(size_t descriptor_index)
|
||||
@@ -160,13 +240,13 @@ void D3D12GSRender::upload_and_bind_vertex_shader_constants(size_t descriptor_in
|
||||
};
|
||||
m_device->CreateConstantBufferView(&constant_buffer_view_desc,
|
||||
CD3DX12_CPU_DESCRIPTOR_HANDLE(get_current_resource_storage().descriptors_heap->GetCPUDescriptorHandleForHeapStart())
|
||||
.Offset((INT)descriptor_index, g_descriptor_stride_srv_cbv_uav));
|
||||
.Offset((INT)descriptor_index, m_descriptor_stride_srv_cbv_uav));
|
||||
}
|
||||
|
||||
void D3D12GSRender::upload_and_bind_fragment_shader_constants(size_t descriptor_index)
|
||||
{
|
||||
// Get constant from fragment program
|
||||
size_t buffer_size = m_pso_cache.get_fragment_constants_buffer_size(fragment_program);
|
||||
size_t buffer_size = m_pso_cache.get_fragment_constants_buffer_size(m_fragment_program);
|
||||
// Multiple of 256 never 0
|
||||
buffer_size = (buffer_size + 255) & ~255;
|
||||
|
||||
@@ -174,7 +254,7 @@ void D3D12GSRender::upload_and_bind_fragment_shader_constants(size_t descriptor_
|
||||
|
||||
size_t offset = 0;
|
||||
float *mapped_buffer = m_buffer_data.map<float>(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size));
|
||||
m_pso_cache.fill_fragment_constans_buffer({ mapped_buffer, gsl::narrow<int>(buffer_size) }, fragment_program);
|
||||
m_pso_cache.fill_fragment_constans_buffer({ mapped_buffer, gsl::narrow<int>(buffer_size) }, m_fragment_program);
|
||||
m_buffer_data.unmap(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size));
|
||||
|
||||
D3D12_CONSTANT_BUFFER_VIEW_DESC constant_buffer_view_desc = {
|
||||
@@ -183,51 +263,11 @@ void D3D12GSRender::upload_and_bind_fragment_shader_constants(size_t descriptor_
|
||||
};
|
||||
m_device->CreateConstantBufferView(&constant_buffer_view_desc,
|
||||
CD3DX12_CPU_DESCRIPTOR_HANDLE(get_current_resource_storage().descriptors_heap->GetCPUDescriptorHandleForHeapStart())
|
||||
.Offset((INT)descriptor_index, g_descriptor_stride_srv_cbv_uav));
|
||||
.Offset((INT)descriptor_index, m_descriptor_stride_srv_cbv_uav));
|
||||
}
|
||||
|
||||
|
||||
std::tuple<D3D12_VERTEX_BUFFER_VIEW, size_t> D3D12GSRender::upload_inlined_vertex_array()
|
||||
{
|
||||
UINT offset = 0;
|
||||
m_IASet.clear();
|
||||
// Bind attributes
|
||||
for (int index = 0; index < rsx::limits::vertex_count; ++index)
|
||||
{
|
||||
const auto &info = vertex_arrays_info[index];
|
||||
|
||||
if (!info.size) // disabled
|
||||
continue;
|
||||
|
||||
D3D12_INPUT_ELEMENT_DESC IAElement = {};
|
||||
IAElement.SemanticName = "TEXCOORD";
|
||||
IAElement.SemanticIndex = (UINT)index;
|
||||
IAElement.InputSlot = 0;
|
||||
IAElement.Format = get_vertex_attribute_format(info.type, info.size);
|
||||
IAElement.AlignedByteOffset = offset;
|
||||
IAElement.InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA;
|
||||
IAElement.InstanceDataStepRate = 0;
|
||||
m_IASet.push_back(IAElement);
|
||||
|
||||
offset += rsx::get_vertex_type_size_on_host(info.type, info.size);
|
||||
}
|
||||
|
||||
// Copy inline buffer
|
||||
size_t buffer_size = inline_vertex_array.size() * sizeof(int);
|
||||
size_t heap_offset = m_buffer_data.alloc<D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT>(buffer_size);
|
||||
void *mapped_buffer = m_buffer_data.map<void>(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size));
|
||||
write_inline_array_to_buffer(mapped_buffer);
|
||||
m_buffer_data.unmap(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size));
|
||||
|
||||
D3D12_VERTEX_BUFFER_VIEW vertex_buffer_view =
|
||||
{
|
||||
m_buffer_data.get_heap()->GetGPUVirtualAddress() + heap_offset,
|
||||
(UINT)buffer_size,
|
||||
(UINT)offset
|
||||
};
|
||||
|
||||
return std::make_tuple(vertex_buffer_view, (u32)buffer_size / offset);
|
||||
}
|
||||
|
||||
std::tuple<D3D12_INDEX_BUFFER_VIEW, size_t> D3D12GSRender::generate_index_buffer_for_emulated_primitives_array(const std::vector<std::pair<u32, u32> > &vertex_ranges)
|
||||
{
|
||||
@@ -258,55 +298,48 @@ std::tuple<D3D12_INDEX_BUFFER_VIEW, size_t> D3D12GSRender::generate_index_buffer
|
||||
return std::make_tuple(index_buffer_view, index_count);
|
||||
}
|
||||
|
||||
std::tuple<bool, size_t> D3D12GSRender::upload_and_set_vertex_index_data(ID3D12GraphicsCommandList *command_list)
|
||||
std::tuple<bool, size_t, std::vector<D3D12_SHADER_RESOURCE_VIEW_DESC>> D3D12GSRender::upload_and_set_vertex_index_data(ID3D12GraphicsCommandList *command_list)
|
||||
{
|
||||
if (draw_command == Draw_command::draw_command_inlined_array)
|
||||
if (draw_command == rsx::draw_command::inlined_array)
|
||||
{
|
||||
size_t vertex_count;
|
||||
D3D12_VERTEX_BUFFER_VIEW vertex_buffer_view;
|
||||
std::tie(vertex_buffer_view, vertex_count) = upload_inlined_vertex_array();
|
||||
command_list->IASetVertexBuffers(0, (UINT)1, &vertex_buffer_view);
|
||||
std::vector<D3D12_SHADER_RESOURCE_VIEW_DESC> vertex_buffer_view;
|
||||
std::tie(vertex_buffer_view, vertex_count) = upload_inlined_vertex_array(
|
||||
vertex_arrays_info,
|
||||
{ (const gsl::byte*) inline_vertex_array.data(), gsl::narrow<int>(inline_vertex_array.size() * sizeof(uint)) },
|
||||
m_buffer_data, m_vertex_buffer_data.Get(), command_list);
|
||||
|
||||
if (is_primitive_native(draw_mode))
|
||||
return std::make_tuple(false, vertex_count);
|
||||
return std::make_tuple(false, vertex_count, vertex_buffer_view);
|
||||
|
||||
D3D12_INDEX_BUFFER_VIEW index_buffer_view;
|
||||
size_t index_count;
|
||||
std::tie(index_buffer_view, index_count) = generate_index_buffer_for_emulated_primitives_array({ { 0, (u32)vertex_count } });
|
||||
command_list->IASetIndexBuffer(&index_buffer_view);
|
||||
return std::make_tuple(true, index_count);
|
||||
return std::make_tuple(true, index_count, vertex_buffer_view);
|
||||
}
|
||||
|
||||
if (draw_command == Draw_command::draw_command_array)
|
||||
if (draw_command == rsx::draw_command::array)
|
||||
{
|
||||
const std::vector<D3D12_VERTEX_BUFFER_VIEW> &vertex_buffer_views = upload_vertex_attributes(first_count_commands);
|
||||
command_list->IASetVertexBuffers(0, (UINT)vertex_buffer_views.size(), vertex_buffer_views.data());
|
||||
|
||||
if (is_primitive_native(draw_mode))
|
||||
{
|
||||
// Index count
|
||||
size_t vertex_count = 0;
|
||||
for (const auto &pair : first_count_commands)
|
||||
vertex_count += pair.second;
|
||||
return std::make_tuple(false, vertex_count);
|
||||
size_t vertex_count = get_vertex_count(first_count_commands);
|
||||
return std::make_tuple(false, vertex_count, upload_vertex_attributes(first_count_commands, command_list));
|
||||
}
|
||||
|
||||
D3D12_INDEX_BUFFER_VIEW index_buffer_view;
|
||||
size_t index_count;
|
||||
std::tie(index_buffer_view, index_count) = generate_index_buffer_for_emulated_primitives_array(first_count_commands);
|
||||
command_list->IASetIndexBuffer(&index_buffer_view);
|
||||
return std::make_tuple(true, index_count);
|
||||
return std::make_tuple(true, index_count, upload_vertex_attributes(first_count_commands, command_list));
|
||||
}
|
||||
|
||||
assert(draw_command == Draw_command::draw_command_indexed);
|
||||
assert(draw_command == rsx::draw_command::indexed);
|
||||
|
||||
// Index count
|
||||
size_t index_count = 0;
|
||||
for (const auto &pair : first_count_commands)
|
||||
index_count += pair.second;
|
||||
index_count = get_index_count(draw_mode, gsl::narrow<int>(index_count));
|
||||
size_t index_count = get_index_count(draw_mode, gsl::narrow<int>(get_vertex_count(first_count_commands)));
|
||||
|
||||
Index_array_type indexed_type = to_index_array_type(rsx::method_registers[NV4097_SET_INDEX_ARRAY_DMA] >> 4);
|
||||
rsx::index_array_type indexed_type = rsx::to_index_array_type(rsx::method_registers[NV4097_SET_INDEX_ARRAY_DMA] >> 4);
|
||||
size_t index_size = get_index_type_size(indexed_type);
|
||||
|
||||
// Alloc
|
||||
@@ -316,13 +349,13 @@ std::tuple<bool, size_t> D3D12GSRender::upload_and_set_vertex_index_data(ID3D12G
|
||||
void *mapped_buffer = m_buffer_data.map<void>(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size));
|
||||
u32 min_index, max_index;
|
||||
|
||||
if (indexed_type == Index_array_type::unsigned_16b)
|
||||
if (indexed_type == rsx::index_array_type::u16)
|
||||
{
|
||||
gsl::span<u16> dst = { (u16*)mapped_buffer, gsl::narrow<int>(buffer_size / index_size) };
|
||||
std::tie(min_index, max_index) = write_index_array_data_to_buffer(dst, draw_mode, first_count_commands);
|
||||
}
|
||||
|
||||
if (indexed_type == Index_array_type::unsigned_32b)
|
||||
if (indexed_type == rsx::index_array_type::u32)
|
||||
{
|
||||
gsl::span<u32> dst = { (u32*)mapped_buffer, gsl::narrow<int>(buffer_size / index_size) };
|
||||
std::tie(min_index, max_index) = write_index_array_data_to_buffer(dst, draw_mode, first_count_commands);
|
||||
@@ -334,13 +367,10 @@ std::tuple<bool, size_t> D3D12GSRender::upload_and_set_vertex_index_data(ID3D12G
|
||||
(UINT)buffer_size,
|
||||
get_index_type(indexed_type)
|
||||
};
|
||||
m_timers.m_buffer_upload_size += buffer_size;
|
||||
m_timers.buffer_upload_size += buffer_size;
|
||||
command_list->IASetIndexBuffer(&index_buffer_view);
|
||||
|
||||
const std::vector<D3D12_VERTEX_BUFFER_VIEW> &vertex_buffer_views = upload_vertex_attributes({ std::make_pair(0, max_index + 1) });
|
||||
command_list->IASetVertexBuffers(0, (UINT)vertex_buffer_views.size(), vertex_buffer_views.data());
|
||||
|
||||
return std::make_tuple(true, index_count);
|
||||
return std::make_tuple(true, index_count, upload_vertex_attributes({ std::make_pair(0, max_index + 1) }, command_list));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -42,18 +42,30 @@ std::string getFunctionImp(FUNCTION f)
|
||||
return "float4(1., 1., 1., 1.)";
|
||||
case FUNCTION::FUNCTION_FRACT:
|
||||
return "frac($0)";
|
||||
case FUNCTION::FUNCTION_TEXTURE_SAMPLE:
|
||||
case FUNCTION::FUNCTION_TEXTURE_SAMPLE1D:
|
||||
return "$t.Sample($tsampler, $0.x)";
|
||||
case FUNCTION::FUNCTION_TEXTURE_SAMPLE1D_PROJ:
|
||||
return "$t.Sample($tsampler, ($0.x / $0.w))";
|
||||
case FUNCTION::FUNCTION_TEXTURE_SAMPLE1D_LOD:
|
||||
return "$t.SampleLevel($tsampler, $0.x, $1)";
|
||||
case FUNCTION::FUNCTION_TEXTURE_SAMPLE2D:
|
||||
return "$t.Sample($tsampler, $0.xy * $t_scale)";
|
||||
case FUNCTION::FUNCTION_TEXTURE_SAMPLE_PROJ:
|
||||
return "$t.Sample($tsampler, ($0.xy / $0.z) * $t_scale)";
|
||||
case FUNCTION::FUNCTION_TEXTURE_SAMPLE_LOD:
|
||||
return "$t.SampleLevel($tsampler, ($0.xy / $0.z) * $t_scale, $1)";
|
||||
case FUNCTION::FUNCTION_TEXTURE_CUBE_SAMPLE:
|
||||
case FUNCTION::FUNCTION_TEXTURE_SAMPLE2D_PROJ:
|
||||
return "$t.Sample($tsampler, ($0.xy / $0.w) * $t_scale)";
|
||||
case FUNCTION::FUNCTION_TEXTURE_SAMPLE2D_LOD:
|
||||
return "$t.SampleLevel($tsampler, $0.xy * $t_scale, $1)";
|
||||
case FUNCTION::FUNCTION_TEXTURE_SAMPLECUBE:
|
||||
return "$t.Sample($tsampler, $0.xyz)";
|
||||
case FUNCTION::FUNCTION_TEXTURE_CUBE_SAMPLE_PROJ:
|
||||
case FUNCTION::FUNCTION_TEXTURE_SAMPLECUBE_PROJ:
|
||||
return "$t.Sample($tsampler, ($0.xyz / $0.w))";
|
||||
case FUNCTION::FUNCTION_TEXTURE_CUBE_SAMPLE_LOD:
|
||||
return "$t.SampleLevel($tsampler, ($0.xyz / $0.w), $1)";
|
||||
case FUNCTION::FUNCTION_TEXTURE_SAMPLECUBE_LOD:
|
||||
return "$t.SampleLevel($tsampler, $0.xyz, $1)";
|
||||
case FUNCTION::FUNCTION_TEXTURE_SAMPLE3D:
|
||||
return "$t.Sample($tsampler, $0.xyz)";
|
||||
case FUNCTION::FUNCTION_TEXTURE_SAMPLE3D_PROJ:
|
||||
return "$t.Sample($tsampler, ($0.xyz / $0.w))";
|
||||
case FUNCTION::FUNCTION_TEXTURE_SAMPLE3D_LOD:
|
||||
return "$t.SampleLevel($tsampler, $0.xyz, $1)";
|
||||
case FUNCTION::FUNCTION_DFDX:
|
||||
return "ddx($0)";
|
||||
case FUNCTION::FUNCTION_DFDY:
|
||||
@@ -81,4 +93,40 @@ std::string compareFunctionImp(COMPARE f, const std::string &Op0, const std::str
|
||||
return "(" + Op0 + " != " + Op1 + ")";
|
||||
}
|
||||
}
|
||||
|
||||
void insert_d3d12_legacy_function(std::ostream& OS)
|
||||
{
|
||||
OS << "float4 divsq_legacy(float4 num, float4 denum)\n";
|
||||
OS << "{\n";
|
||||
OS << " return num / sqrt(max(denum.xxxx, 1.E-10));\n";
|
||||
OS << "}\n";
|
||||
|
||||
OS << "float4 rcp_legacy(float4 denum)\n";
|
||||
OS << "{\n";
|
||||
OS << " return 1. / denum;\n";
|
||||
OS << "}\n";
|
||||
|
||||
OS << "float4 rsq_legacy(float4 val)\n";
|
||||
OS << "{\n";
|
||||
OS << " return float(1.0 / sqrt(max(val.x, 1.E-10))).xxxx;\n";
|
||||
OS << "}\n\n";
|
||||
|
||||
OS << "float4 log2_legacy(float4 val)\n";
|
||||
OS << "{\n";
|
||||
OS << " return log2(max(val.x, 1.E-10)).xxxx;\n";
|
||||
OS << "}\n\n";
|
||||
|
||||
OS << "float4 lit_legacy(float4 val)";
|
||||
OS << "{\n";
|
||||
OS << " float4 clamped_val = val;\n";
|
||||
OS << " clamped_val.x = max(val.x, 0);\n";
|
||||
OS << " clamped_val.y = max(val.y, 0);\n";
|
||||
OS << " float4 result;\n";
|
||||
OS << " result.x = 1.0;\n";
|
||||
OS << " result.w = 1.;\n";
|
||||
OS << " result.y = clamped_val.x;\n";
|
||||
OS << " result.z = clamped_val.x > 0.0 ? exp(clamped_val.w * log(max(clamped_val.y, 1.E-10))) : 0.0;\n";
|
||||
OS << " return result;\n";
|
||||
OS << "}\n\n";
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -5,3 +5,5 @@
|
||||
std::string getFloatTypeNameImp(size_t elementCount);
|
||||
std::string getFunctionImp(FUNCTION f);
|
||||
std::string compareFunctionImp(COMPARE f, const std::string &Op0, const std::string &Op1);
|
||||
|
||||
void insert_d3d12_legacy_function(std::ostream&);
|
||||
|
||||
@@ -262,92 +262,99 @@ D3D12_FILTER get_texture_filter(u8 min_filter, u8 mag_filter)
|
||||
return D3D12_ENCODE_BASIC_FILTER(min, mag, mip, D3D12_FILTER_REDUCTION_TYPE_STANDARD);
|
||||
}
|
||||
|
||||
D3D12_PRIMITIVE_TOPOLOGY get_primitive_topology(Primitive_type draw_mode)
|
||||
D3D12_PRIMITIVE_TOPOLOGY get_primitive_topology(rsx::primitive_type draw_mode)
|
||||
{
|
||||
switch (draw_mode)
|
||||
{
|
||||
case Primitive_type::points: return D3D_PRIMITIVE_TOPOLOGY_POINTLIST;
|
||||
case Primitive_type::lines: return D3D_PRIMITIVE_TOPOLOGY_LINELIST;
|
||||
case Primitive_type::line_loop: return D3D_PRIMITIVE_TOPOLOGY_LINELIST_ADJ;
|
||||
case Primitive_type::line_strip: return D3D_PRIMITIVE_TOPOLOGY_LINESTRIP;
|
||||
case Primitive_type::triangles: return D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
|
||||
case Primitive_type::triangle_strip: return D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
|
||||
case Primitive_type::triangle_fan: return D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
|
||||
case Primitive_type::quads: return D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
|
||||
case Primitive_type::quad_strip: return D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
|
||||
case Primitive_type::polygon: return D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
|
||||
case rsx::primitive_type::points: return D3D_PRIMITIVE_TOPOLOGY_POINTLIST;
|
||||
case rsx::primitive_type::lines: return D3D_PRIMITIVE_TOPOLOGY_LINELIST;
|
||||
case rsx::primitive_type::line_loop: return D3D_PRIMITIVE_TOPOLOGY_LINELIST_ADJ;
|
||||
case rsx::primitive_type::line_strip: return D3D_PRIMITIVE_TOPOLOGY_LINESTRIP;
|
||||
case rsx::primitive_type::triangles: return D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
|
||||
case rsx::primitive_type::triangle_strip: return D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
|
||||
case rsx::primitive_type::triangle_fan: return D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
|
||||
case rsx::primitive_type::quads: return D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
|
||||
case rsx::primitive_type::quad_strip: return D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
|
||||
case rsx::primitive_type::polygon: return D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
|
||||
}
|
||||
throw EXCEPTION("Invalid draw mode (0x%x)", draw_mode);
|
||||
}
|
||||
|
||||
D3D12_PRIMITIVE_TOPOLOGY_TYPE get_primitive_topology_type(Primitive_type draw_mode)
|
||||
D3D12_PRIMITIVE_TOPOLOGY_TYPE get_primitive_topology_type(rsx::primitive_type draw_mode)
|
||||
{
|
||||
switch (draw_mode)
|
||||
{
|
||||
case Primitive_type::points: return D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT;
|
||||
case Primitive_type::lines: return D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE;
|
||||
case Primitive_type::line_strip: return D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE;
|
||||
case Primitive_type::triangles: return D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
|
||||
case Primitive_type::triangle_strip: return D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
|
||||
case Primitive_type::triangle_fan: return D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
|
||||
case Primitive_type::quads: return D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
|
||||
case Primitive_type::quad_strip: return D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
|
||||
case Primitive_type::polygon: return D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
|
||||
case Primitive_type::line_loop: return D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE;
|
||||
case rsx::primitive_type::points: return D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT;
|
||||
case rsx::primitive_type::lines: return D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE;
|
||||
case rsx::primitive_type::line_strip: return D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE;
|
||||
case rsx::primitive_type::triangles: return D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
|
||||
case rsx::primitive_type::triangle_strip: return D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
|
||||
case rsx::primitive_type::triangle_fan: return D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
|
||||
case rsx::primitive_type::quads: return D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
|
||||
case rsx::primitive_type::quad_strip: return D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
|
||||
case rsx::primitive_type::polygon: return D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
|
||||
case rsx::primitive_type::line_loop: return D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE;
|
||||
}
|
||||
throw EXCEPTION("Invalid or unsupported draw mode (0x%x)", draw_mode);
|
||||
}
|
||||
|
||||
DXGI_FORMAT get_color_surface_format(u8 format)
|
||||
DXGI_FORMAT get_color_surface_format(rsx::surface_color_format format)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case CELL_GCM_SURFACE_R5G6B5: return DXGI_FORMAT_B5G6R5_UNORM;
|
||||
case CELL_GCM_SURFACE_X8R8G8B8_O8R8G8B8: return DXGI_FORMAT_B8G8R8X8_UNORM; //BIT.TRIP Runner2 use this
|
||||
case CELL_GCM_SURFACE_A8R8G8B8: return DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
case CELL_GCM_SURFACE_F_W16Z16Y16X16: return DXGI_FORMAT_R16G16B16A16_FLOAT;
|
||||
case CELL_GCM_SURFACE_F_X32: return DXGI_FORMAT_R32_FLOAT;
|
||||
case CELL_GCM_SURFACE_A8B8G8R8: return DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
case rsx::surface_color_format::r5g6b5: return DXGI_FORMAT_B5G6R5_UNORM;
|
||||
case rsx::surface_color_format::x8r8g8b8_o8r8g8b8:
|
||||
case rsx::surface_color_format::x8r8g8b8_z8r8g8b8:
|
||||
case rsx::surface_color_format::x8b8g8r8_o8b8g8r8:
|
||||
case rsx::surface_color_format::x8b8g8r8_z8b8g8r8:
|
||||
return DXGI_FORMAT_B8G8R8X8_UNORM; //BIT.TRIP Runner2 use this
|
||||
case rsx::surface_color_format::a8b8g8r8:
|
||||
case rsx::surface_color_format::a8r8g8b8: return DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
case rsx::surface_color_format::b8: return DXGI_FORMAT_R8_UNORM;
|
||||
case rsx::surface_color_format::g8b8: return DXGI_FORMAT_R8G8_UNORM;
|
||||
case rsx::surface_color_format::w16z16y16x16: return DXGI_FORMAT_R16G16B16A16_FLOAT;
|
||||
case rsx::surface_color_format::w32z32y32x32: return DXGI_FORMAT_R32G32B32A32_FLOAT;
|
||||
case rsx::surface_color_format::x32: return DXGI_FORMAT_R32_FLOAT;
|
||||
}
|
||||
throw EXCEPTION("Invalid format (0x%x)", format);
|
||||
}
|
||||
|
||||
DXGI_FORMAT get_depth_stencil_surface_format(u8 format)
|
||||
DXGI_FORMAT get_depth_stencil_surface_format(rsx::surface_depth_format format)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case CELL_GCM_SURFACE_Z16: return DXGI_FORMAT_D16_UNORM;
|
||||
case CELL_GCM_SURFACE_Z24S8: return DXGI_FORMAT_D24_UNORM_S8_UINT;
|
||||
case rsx::surface_depth_format::z16: return DXGI_FORMAT_D16_UNORM;
|
||||
case rsx::surface_depth_format::z24s8: return DXGI_FORMAT_D24_UNORM_S8_UINT;
|
||||
}
|
||||
throw EXCEPTION("Invalid format (0x%x)", format);
|
||||
}
|
||||
|
||||
DXGI_FORMAT get_depth_stencil_surface_clear_format(u8 format)
|
||||
DXGI_FORMAT get_depth_stencil_surface_clear_format(rsx::surface_depth_format format)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case CELL_GCM_SURFACE_Z16: return DXGI_FORMAT_D16_UNORM;
|
||||
case CELL_GCM_SURFACE_Z24S8: return DXGI_FORMAT_D24_UNORM_S8_UINT;
|
||||
case rsx::surface_depth_format::z16: return DXGI_FORMAT_D16_UNORM;
|
||||
case rsx::surface_depth_format::z24s8: return DXGI_FORMAT_D24_UNORM_S8_UINT;
|
||||
}
|
||||
throw EXCEPTION("Invalid format (0x%x)", format);
|
||||
}
|
||||
|
||||
DXGI_FORMAT get_depth_stencil_typeless_surface_format(u8 format)
|
||||
DXGI_FORMAT get_depth_stencil_typeless_surface_format(rsx::surface_depth_format format)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case CELL_GCM_SURFACE_Z16: return DXGI_FORMAT_R16_TYPELESS;
|
||||
case CELL_GCM_SURFACE_Z24S8: return DXGI_FORMAT_R24G8_TYPELESS;
|
||||
case rsx::surface_depth_format::z16: return DXGI_FORMAT_R16_TYPELESS;
|
||||
case rsx::surface_depth_format::z24s8: return DXGI_FORMAT_R24G8_TYPELESS;
|
||||
}
|
||||
throw EXCEPTION("Invalid format (0x%x)", format);
|
||||
}
|
||||
|
||||
DXGI_FORMAT get_depth_samplable_surface_format(u8 format)
|
||||
DXGI_FORMAT get_depth_samplable_surface_format(rsx::surface_depth_format format)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case CELL_GCM_SURFACE_Z16: return DXGI_FORMAT_R16_FLOAT;
|
||||
case CELL_GCM_SURFACE_Z24S8: return DXGI_FORMAT_R24_UNORM_X8_TYPELESS;
|
||||
case rsx::surface_depth_format::z16: return DXGI_FORMAT_R16_UNORM;
|
||||
case rsx::surface_depth_format::z24s8: return DXGI_FORMAT_R24_UNORM_X8_TYPELESS;
|
||||
}
|
||||
throw EXCEPTION("Invalid format (0x%x)", format);
|
||||
}
|
||||
@@ -363,21 +370,21 @@ BOOL get_front_face_ccw(u32 ffv)
|
||||
throw EXCEPTION("Invalid front face value (0x%x)", ffv);
|
||||
}
|
||||
|
||||
DXGI_FORMAT get_index_type(Index_array_type index_type)
|
||||
DXGI_FORMAT get_index_type(rsx::index_array_type index_type)
|
||||
{
|
||||
switch (index_type)
|
||||
{
|
||||
case Index_array_type::unsigned_16b: return DXGI_FORMAT_R16_UINT;
|
||||
case Index_array_type::unsigned_32b: return DXGI_FORMAT_R32_UINT;
|
||||
case rsx::index_array_type::u16: return DXGI_FORMAT_R16_UINT;
|
||||
case rsx::index_array_type::u32: return DXGI_FORMAT_R32_UINT;
|
||||
}
|
||||
throw EXCEPTION("Invalid index_type (0x%x)", index_type);
|
||||
}
|
||||
|
||||
DXGI_FORMAT get_vertex_attribute_format(Vertex_base_type type, u8 size)
|
||||
DXGI_FORMAT get_vertex_attribute_format(rsx::vertex_base_type type, u8 size)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case Vertex_base_type::s1:
|
||||
case rsx::vertex_base_type::s1:
|
||||
{
|
||||
switch (size)
|
||||
{
|
||||
@@ -388,7 +395,7 @@ DXGI_FORMAT get_vertex_attribute_format(Vertex_base_type type, u8 size)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Vertex_base_type::f:
|
||||
case rsx::vertex_base_type::f:
|
||||
{
|
||||
switch (size)
|
||||
{
|
||||
@@ -399,7 +406,7 @@ DXGI_FORMAT get_vertex_attribute_format(Vertex_base_type type, u8 size)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Vertex_base_type::sf:
|
||||
case rsx::vertex_base_type::sf:
|
||||
{
|
||||
switch (size)
|
||||
{
|
||||
@@ -410,7 +417,7 @@ DXGI_FORMAT get_vertex_attribute_format(Vertex_base_type type, u8 size)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Vertex_base_type::ub:
|
||||
case rsx::vertex_base_type::ub:
|
||||
{
|
||||
switch (size)
|
||||
{
|
||||
@@ -421,7 +428,7 @@ DXGI_FORMAT get_vertex_attribute_format(Vertex_base_type type, u8 size)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Vertex_base_type::s32k:
|
||||
case rsx::vertex_base_type::s32k:
|
||||
{
|
||||
switch (size)
|
||||
{
|
||||
@@ -432,7 +439,7 @@ DXGI_FORMAT get_vertex_attribute_format(Vertex_base_type type, u8 size)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Vertex_base_type::cmp:
|
||||
case rsx::vertex_base_type::cmp:
|
||||
{
|
||||
switch (size)
|
||||
{
|
||||
@@ -443,7 +450,7 @@ DXGI_FORMAT get_vertex_attribute_format(Vertex_base_type type, u8 size)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Vertex_base_type::ub256:
|
||||
case rsx::vertex_base_type::ub256:
|
||||
{
|
||||
switch (size)
|
||||
{
|
||||
|
||||
@@ -56,37 +56,37 @@ D3D12_FILTER get_texture_filter(u8 min_filter, u8 mag_filter);
|
||||
/**
|
||||
* Convert draw mode to D3D12_PRIMITIVE_TOPOLOGY
|
||||
*/
|
||||
D3D12_PRIMITIVE_TOPOLOGY get_primitive_topology(Primitive_type draw_mode);
|
||||
D3D12_PRIMITIVE_TOPOLOGY get_primitive_topology(rsx::primitive_type draw_mode);
|
||||
|
||||
/**
|
||||
* Convert draw mode to D3D12_PRIMITIVE_TOPOLOGY_TYPE
|
||||
*/
|
||||
D3D12_PRIMITIVE_TOPOLOGY_TYPE get_primitive_topology_type(Primitive_type draw_mode);
|
||||
D3D12_PRIMITIVE_TOPOLOGY_TYPE get_primitive_topology_type(rsx::primitive_type draw_mode);
|
||||
|
||||
/**
|
||||
* Convert color surface format to DXGI_FORMAT
|
||||
*/
|
||||
DXGI_FORMAT get_color_surface_format(u8 format);
|
||||
DXGI_FORMAT get_color_surface_format(rsx::surface_color_format format);
|
||||
|
||||
/**
|
||||
* Convert depth stencil surface format to DXGI_FORMAT
|
||||
*/
|
||||
DXGI_FORMAT get_depth_stencil_surface_format(u8 format);
|
||||
DXGI_FORMAT get_depth_stencil_surface_format(rsx::surface_depth_format format);
|
||||
|
||||
/**
|
||||
*Convert depth stencil surface format to DXGI_FORMAT suited for clear value
|
||||
*/
|
||||
DXGI_FORMAT get_depth_stencil_surface_clear_format(u8 format);
|
||||
DXGI_FORMAT get_depth_stencil_surface_clear_format(rsx::surface_depth_format format);
|
||||
|
||||
/**
|
||||
* Convert depth surface format to a typeless DXGI_FORMAT
|
||||
*/
|
||||
DXGI_FORMAT get_depth_stencil_typeless_surface_format(u8 format);
|
||||
DXGI_FORMAT get_depth_stencil_typeless_surface_format(rsx::surface_depth_format format);
|
||||
|
||||
/**
|
||||
* Convert depth surface format to a DXGI_FORMAT that can be depth sampled
|
||||
*/
|
||||
DXGI_FORMAT get_depth_samplable_surface_format(u8 format);
|
||||
DXGI_FORMAT get_depth_samplable_surface_format(rsx::surface_depth_format format);
|
||||
|
||||
/**
|
||||
* Convert front face value to bool value telling wheter front face is counterclockwise or not
|
||||
@@ -96,12 +96,12 @@ BOOL get_front_face_ccw(u32 set_front_face_value);
|
||||
/**
|
||||
* Convert index type to DXGI_FORMAT
|
||||
*/
|
||||
DXGI_FORMAT get_index_type(Index_array_type index_type);
|
||||
DXGI_FORMAT get_index_type(rsx::index_array_type index_type);
|
||||
|
||||
/**
|
||||
* Convert vertex attribute format and size to DXGI_FORMAT
|
||||
*/
|
||||
DXGI_FORMAT get_vertex_attribute_format(Vertex_base_type type, u8 size);
|
||||
DXGI_FORMAT get_vertex_attribute_format(rsx::vertex_base_type type, u8 size);
|
||||
|
||||
/**
|
||||
* Convert scissor register value to D3D12_RECT
|
||||
|
||||
@@ -39,22 +39,6 @@ void D3D12FragmentDecompiler::insertHeader(std::stringstream & OS)
|
||||
OS << " float4x4 scaleOffsetMat;" << std::endl;
|
||||
OS << " int isAlphaTested;" << std::endl;
|
||||
OS << " float alphaRef;" << std::endl;
|
||||
OS << " int tex0_is_unorm;" << std::endl;
|
||||
OS << " int tex1_is_unorm;" << std::endl;
|
||||
OS << " int tex2_is_unorm;" << std::endl;
|
||||
OS << " int tex3_is_unorm;" << std::endl;
|
||||
OS << " int tex4_is_unorm;" << std::endl;
|
||||
OS << " int tex5_is_unorm;" << std::endl;
|
||||
OS << " int tex6_is_unorm;" << std::endl;
|
||||
OS << " int tex7_is_unorm;" << std::endl;
|
||||
OS << " int tex8_is_unorm;" << std::endl;
|
||||
OS << " int tex9_is_unorm;" << std::endl;
|
||||
OS << " int tex10_is_unorm;" << std::endl;
|
||||
OS << " int tex11_is_unorm;" << std::endl;
|
||||
OS << " int tex12_is_unorm;" << std::endl;
|
||||
OS << " int tex13_is_unorm;" << std::endl;
|
||||
OS << " int tex14_is_unorm;" << std::endl;
|
||||
OS << " int tex15_is_unorm;" << std::endl;
|
||||
OS << "};" << std::endl;
|
||||
}
|
||||
|
||||
@@ -107,32 +91,50 @@ void D3D12FragmentDecompiler::insertConstants(std::stringstream & OS)
|
||||
{
|
||||
OS << "cbuffer CONSTANT : register(b2)" << std::endl;
|
||||
OS << "{" << std::endl;
|
||||
for (ParamType PT : m_parr.params[PF_PARAM_UNIFORM])
|
||||
for (const ParamType &PT : m_parr.params[PF_PARAM_UNIFORM])
|
||||
{
|
||||
if (PT.type == "sampler2D" || PT.type == "samplerCube")
|
||||
if (PT.type == "sampler1D" || PT.type == "sampler2D" || PT.type == "samplerCube" || PT.type == "sampler3D")
|
||||
continue;
|
||||
for (ParamItem PI : PT.items)
|
||||
for (const ParamItem &PI : PT.items)
|
||||
OS << " " << PT.type << " " << PI.name << ";" << std::endl;
|
||||
}
|
||||
OS << "};" << std::endl << std::endl;
|
||||
|
||||
for (ParamType PT : m_parr.params[PF_PARAM_UNIFORM])
|
||||
for (const ParamType &PT : m_parr.params[PF_PARAM_UNIFORM])
|
||||
{
|
||||
if (PT.type == "sampler2D")
|
||||
if (PT.type == "sampler1D")
|
||||
{
|
||||
for (ParamItem PI : PT.items)
|
||||
for (const ParamItem &PI : PT.items)
|
||||
{
|
||||
size_t textureIndex = atoi(PI.name.data() + 3);
|
||||
OS << "Texture2D " << PI.name << " : register(t" << textureIndex << ");" << std::endl;
|
||||
OS << "Texture1D " << PI.name << " : register(t" << textureIndex + 16 << ");" << std::endl;
|
||||
OS << "sampler " << PI.name << "sampler : register(s" << textureIndex << ");" << std::endl;
|
||||
}
|
||||
}
|
||||
else if (PT.type == "sampler2D")
|
||||
{
|
||||
for (const ParamItem &PI : PT.items)
|
||||
{
|
||||
size_t textureIndex = atoi(PI.name.data() + 3);
|
||||
OS << "Texture2D " << PI.name << " : register(t" << textureIndex + 16 << ");" << std::endl;
|
||||
OS << "sampler " << PI.name << "sampler : register(s" << textureIndex << ");" << std::endl;
|
||||
}
|
||||
}
|
||||
else if (PT.type == "sampler3D")
|
||||
{
|
||||
for (const ParamItem &PI : PT.items)
|
||||
{
|
||||
size_t textureIndex = atoi(PI.name.data() + 3);
|
||||
OS << "Texture3D " << PI.name << " : register(t" << textureIndex + 16 << ");" << std::endl;
|
||||
OS << "sampler " << PI.name << "sampler : register(s" << textureIndex << ");" << std::endl;
|
||||
}
|
||||
}
|
||||
else if (PT.type == "samplerCube")
|
||||
{
|
||||
for (ParamItem PI : PT.items)
|
||||
for (const ParamItem &PI : PT.items)
|
||||
{
|
||||
size_t textureIndex = atoi(PI.name.data() + 3);
|
||||
OS << "TextureCube " << PI.name << " : register(t" << textureIndex << ");" << std::endl;
|
||||
OS << "TextureCube " << PI.name << " : register(t" << textureIndex + 16 << ");" << std::endl;
|
||||
OS << "sampler " << PI.name << "sampler : register(s" << textureIndex << ");" << std::endl;
|
||||
}
|
||||
}
|
||||
@@ -141,57 +143,64 @@ void D3D12FragmentDecompiler::insertConstants(std::stringstream & OS)
|
||||
|
||||
void D3D12FragmentDecompiler::insertMainStart(std::stringstream & OS)
|
||||
{
|
||||
// "lib" function
|
||||
// 0.00001 is used as "some non zero very little number"
|
||||
OS << "float4 divsq_legacy(float4 num, float4 denum)\n";
|
||||
OS << "{\n";
|
||||
OS << " return num / sqrt(max(denum.xxxx, 0.00001));\n";
|
||||
OS << "}\n";
|
||||
|
||||
OS << "float4 rcp_legacy(float4 denum)\n";
|
||||
OS << "{\n";
|
||||
OS << " return 1. / denum;\n";
|
||||
OS << "}\n";
|
||||
|
||||
OS << "float4 rsq_legacy(float4 denum)\n";
|
||||
OS << "{\n";
|
||||
OS << " return 1. / sqrt(max(denum, 0.00001));\n";
|
||||
OS << "}\n";
|
||||
|
||||
insert_d3d12_legacy_function(OS);
|
||||
|
||||
const std::set<std::string> output_value =
|
||||
{
|
||||
"r0", "r1", "r2", "r3", "r4",
|
||||
"h0", "h4", "h6", "h8"
|
||||
"h0", "h2", "h4", "h6", "h8"
|
||||
};
|
||||
OS << "void ps_impl(PixelInput In, inout float4 r0, inout float4 h0, inout float4 r1, inout float4 r2, inout float4 h4, inout float4 r3, inout float4 h6, inout float4 r4, inout float4 h8)" << std::endl;
|
||||
OS << "void ps_impl(bool is_front_face, PixelInput In, inout float4 r0, inout float4 h0, inout float4 r1, inout float4 h2, inout float4 r2, inout float4 h4, inout float4 r3, inout float4 h6, inout float4 r4, inout float4 h8)" << std::endl;
|
||||
OS << "{" << std::endl;
|
||||
for (ParamType PT : m_parr.params[PF_PARAM_IN])
|
||||
for (const ParamType &PT : m_parr.params[PF_PARAM_IN])
|
||||
{
|
||||
for (ParamItem PI : PT.items)
|
||||
for (const ParamItem &PI : PT.items)
|
||||
{
|
||||
if (m_prog.front_back_color_enabled)
|
||||
{
|
||||
if (PI.name == "spec_color" && m_prog.back_color_specular_output)
|
||||
{
|
||||
OS << " float4 spec_color = is_front_face ? In.dst_reg4 : In.spec_color;\n";
|
||||
continue;
|
||||
}
|
||||
if (PI.name == "diff_color" && m_prog.back_color_diffuse_output)
|
||||
{
|
||||
OS << " float4 diff_color = is_front_face ? In.dst_reg3 : In.diff_color;\n";
|
||||
continue;
|
||||
}
|
||||
}
|
||||
OS << " " << PT.type << " " << PI.name << " = In." << PI.name << ";" << std::endl;
|
||||
}
|
||||
}
|
||||
// A bit unclean, but works.
|
||||
OS << " " << "float4 gl_Position = In.Position;" << std::endl;
|
||||
OS << " " << "float4 gl_FragCoord = In.Position;" << std::endl;
|
||||
if (m_prog.origin_mode == rsx::window_origin::bottom)
|
||||
OS << " gl_FragCoord.y = (" << std::to_string(m_prog.height) << " - gl_FragCoord.y);\n";
|
||||
// Declare output
|
||||
for (ParamType PT : m_parr.params[PF_PARAM_NONE])
|
||||
for (const ParamType &PT : m_parr.params[PF_PARAM_NONE])
|
||||
{
|
||||
for (ParamItem PI : PT.items)
|
||||
for (const ParamItem &PI : PT.items)
|
||||
if (output_value.find(PI.name) == output_value.end())
|
||||
OS << " " << PT.type << " " << PI.name << " = float4(0., 0., 0., 0.);" << std::endl;
|
||||
}
|
||||
// Declare texture coordinate scaling component (to handle unormalized texture coordinates)
|
||||
|
||||
for (ParamType PT : m_parr.params[PF_PARAM_UNIFORM])
|
||||
for (const ParamType &PT : m_parr.params[PF_PARAM_UNIFORM])
|
||||
{
|
||||
if (PT.type != "sampler2D")
|
||||
continue;
|
||||
for (const ParamItem& PI : PT.items)
|
||||
{
|
||||
size_t textureIndex = atoi(PI.name.data() + 3);
|
||||
bool is_unorm = !!(m_prog.unnormalized_coords & (1 << textureIndex));
|
||||
if (!is_unorm)
|
||||
{
|
||||
OS << " float2 " << PI.name << "_scale = float2(1., 1.);" << std::endl;
|
||||
continue;
|
||||
}
|
||||
OS << " float2 " << PI.name << "_dim;" << std::endl;
|
||||
OS << " " << PI.name << ".GetDimensions(" << PI.name << "_dim.x, " << PI.name << "_dim.y);" << std::endl;
|
||||
OS << " float2 " << PI.name << "_scale = (!!" << PI.name << "_is_unorm) ? float2(1., 1.) / " << PI.name << "_dim : float2(1., 1.);" << std::endl;
|
||||
OS << " float2 " << PI.name << "_scale = float2(1., 1.) / " << PI.name << "_dim;" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -200,7 +209,7 @@ void D3D12FragmentDecompiler::insertMainEnd(std::stringstream & OS)
|
||||
{
|
||||
OS << "}" << std::endl;
|
||||
OS << std::endl;
|
||||
OS << "PixelOutput main(PixelInput In)" << std::endl;
|
||||
OS << "PixelOutput main(PixelInput In, bool is_front_face : SV_IsFrontFace)" << std::endl;
|
||||
OS << "{" << std::endl;
|
||||
OS << " float4 r0 = float4(0., 0., 0., 0.);" << std::endl;
|
||||
OS << " float4 r1 = float4(0., 0., 0., 0.);" << std::endl;
|
||||
@@ -212,7 +221,7 @@ void D3D12FragmentDecompiler::insertMainEnd(std::stringstream & OS)
|
||||
OS << " float4 h4 = float4(0., 0., 0., 0.);" << std::endl;
|
||||
OS << " float4 h6 = float4(0., 0., 0., 0.);" << std::endl;
|
||||
OS << " float4 h8 = float4(0., 0., 0., 0.);" << std::endl;
|
||||
OS << " ps_impl(In, r0, h0, r1, r2, h4, r3, h6, r4, h8);" << std::endl;
|
||||
OS << " ps_impl(is_front_face, In, r0, h0, r1, h2, r2, h4, r3, h6, r4, h8);" << std::endl;
|
||||
|
||||
const std::pair<std::string, std::string> table[] =
|
||||
{
|
||||
@@ -222,21 +231,52 @@ void D3D12FragmentDecompiler::insertMainEnd(std::stringstream & OS)
|
||||
{ "ocol3", m_ctrl & CELL_GCM_SHADER_CONTROL_32_BITS_EXPORTS ? "r4" : "h8" },
|
||||
};
|
||||
|
||||
size_t num_output = 0;
|
||||
std::string first_output_name;
|
||||
OS << " PixelOutput Out = (PixelOutput)0;" << std::endl;
|
||||
for (int i = 0; i < sizeof(table) / sizeof(*table); ++i)
|
||||
{
|
||||
if (m_parr.HasParam(PF_PARAM_NONE, "float4", table[i].second))
|
||||
{
|
||||
OS << " Out." << table[i].first << " = " << table[i].second << ";" << std::endl;
|
||||
num_output++;
|
||||
if (first_output_name.empty()) first_output_name = table[i].first;
|
||||
}
|
||||
}
|
||||
if (m_ctrl & CELL_GCM_SHADER_CONTROL_DEPTH_EXPORT)
|
||||
OS << " Out.depth = " << ((m_ctrl & CELL_GCM_SHADER_CONTROL_32_BITS_EXPORTS) ? "r1.z;" : "h0.z;") << std::endl;
|
||||
{
|
||||
/**
|
||||
* Note: Naruto Shippuden : Ultimate Ninja Storm 2 sets CELL_GCM_SHADER_CONTROL_32_BITS_EXPORTS in a shader
|
||||
* but it writes depth in r1.z and not h2.z.
|
||||
* Maybe there's a different flag for depth ?
|
||||
*/
|
||||
// OS << " Out.depth = " << ((m_ctrl & CELL_GCM_SHADER_CONTROL_32_BITS_EXPORTS) ? "r1.z;" : "h2.z;") << std::endl;
|
||||
OS << " Out.depth = r1.z;\n";
|
||||
}
|
||||
// Shaders don't always output colors (for instance if they write to depth only)
|
||||
if (num_output > 0)
|
||||
OS << " if (isAlphaTested && Out.ocol0.a <= alphaRef) discard;" << std::endl;
|
||||
if (!first_output_name.empty())
|
||||
{
|
||||
switch (m_prog.alpha_func)
|
||||
{
|
||||
case rsx::comparaison_function::equal:
|
||||
OS << " if (isAlphaTested && Out." << first_output_name << ".a != alphaRef) discard;\n";
|
||||
break;
|
||||
case rsx::comparaison_function::not_equal:
|
||||
OS << " if (isAlphaTested && Out." << first_output_name << ".a == alphaRef) discard;\n";
|
||||
break;
|
||||
case rsx::comparaison_function::less_or_equal:
|
||||
OS << " if (isAlphaTested && Out." << first_output_name << ".a > alphaRef) discard;\n";
|
||||
break;
|
||||
case rsx::comparaison_function::less:
|
||||
OS << " if (isAlphaTested && Out." << first_output_name << ".a >= alphaRef) discard;\n";
|
||||
break;
|
||||
case rsx::comparaison_function::greater:
|
||||
OS << " if (isAlphaTested && Out." << first_output_name << ".a <= alphaRef) discard;\n";
|
||||
break;
|
||||
case rsx::comparaison_function::greater_or_equal:
|
||||
OS << " if (isAlphaTested && Out." << first_output_name << ".a < alphaRef) discard;\n";
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
OS << " return Out;" << std::endl;
|
||||
OS << "}" << std::endl;
|
||||
}
|
||||
|
||||
@@ -58,17 +58,15 @@ void wait_for_command_queue(ID3D12Device *device, ID3D12CommandQueue *command_qu
|
||||
}
|
||||
}
|
||||
|
||||
void D3D12GSRender::Shader::Release()
|
||||
void D3D12GSRender::shader::release()
|
||||
{
|
||||
m_PSO->Release();
|
||||
m_rootSignature->Release();
|
||||
m_vertexBuffer->Release();
|
||||
m_textureDescriptorHeap->Release();
|
||||
m_samplerDescriptorHeap->Release();
|
||||
pso->Release();
|
||||
root_signature->Release();
|
||||
vertex_buffer->Release();
|
||||
texture_descriptor_heap->Release();
|
||||
sampler_descriptor_heap->Release();
|
||||
}
|
||||
|
||||
extern std::function<bool(u32 addr)> gfxHandler;
|
||||
|
||||
bool D3D12GSRender::invalidate_address(u32 addr)
|
||||
{
|
||||
bool result = false;
|
||||
@@ -89,12 +87,6 @@ D3D12DLLManagement::~D3D12DLLManagement()
|
||||
D3D12GSRender::D3D12GSRender()
|
||||
: GSRender(frame_type::DX12), m_d3d12_lib(), m_current_pso({})
|
||||
{
|
||||
gfxHandler = [this](u32 addr) {
|
||||
bool result = invalidate_address(addr);
|
||||
if (result)
|
||||
LOG_WARNING(RSX, "Reporting Cell writing to 0x%x", addr);
|
||||
return result;
|
||||
};
|
||||
if (rpcs3::config.rsx.d3d12.debug_output.value())
|
||||
{
|
||||
Microsoft::WRL::ComPtr<ID3D12Debug> debugInterface;
|
||||
@@ -113,10 +105,10 @@ D3D12GSRender::D3D12GSRender()
|
||||
D3D12_COMMAND_QUEUE_DESC graphic_queue_desc = { D3D12_COMMAND_LIST_TYPE_DIRECT };
|
||||
CHECK_HRESULT(m_device->CreateCommandQueue(&graphic_queue_desc, IID_PPV_ARGS(m_command_queue.GetAddressOf())));
|
||||
|
||||
g_descriptor_stride_srv_cbv_uav = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
|
||||
g_descriptor_stride_dsv = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_DSV);
|
||||
g_descriptor_stride_rtv = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
|
||||
g_descriptor_stride_samplers = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER);
|
||||
m_descriptor_stride_srv_cbv_uav = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
|
||||
m_descriptor_stride_dsv = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_DSV);
|
||||
m_descriptor_stride_rtv = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
|
||||
m_descriptor_stride_samplers = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER);
|
||||
|
||||
// Create swap chain and put them in a descriptor heap as rendertarget
|
||||
DXGI_SWAP_CHAIN_DESC swap_chain = {};
|
||||
@@ -143,33 +135,43 @@ D3D12GSRender::D3D12GSRender()
|
||||
m_device->CreateRenderTargetView(m_backbuffer[1].Get(), &renter_target_view_desc, m_backbuffer_descriptor_heap[1]->GetCPUDescriptorHandleForHeapStart());
|
||||
|
||||
// Common root signatures
|
||||
for (unsigned texture_count = 0; texture_count < 17; texture_count++)
|
||||
for (int vertex_buffer_count = 0; vertex_buffer_count < 17; vertex_buffer_count++) // Some app (naruto ultimate ninja storm 2) uses a shader without inputs...
|
||||
{
|
||||
CD3DX12_DESCRIPTOR_RANGE descriptorRange[] =
|
||||
for (unsigned texture_count = 0; texture_count < 17; texture_count++)
|
||||
{
|
||||
// Scale Offset data
|
||||
CD3DX12_DESCRIPTOR_RANGE(D3D12_DESCRIPTOR_RANGE_TYPE_CBV, 1, 0),
|
||||
// Constants
|
||||
CD3DX12_DESCRIPTOR_RANGE(D3D12_DESCRIPTOR_RANGE_TYPE_CBV, 2, 1),
|
||||
// Textures
|
||||
CD3DX12_DESCRIPTOR_RANGE(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, texture_count, 0),
|
||||
// Samplers
|
||||
CD3DX12_DESCRIPTOR_RANGE(D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, texture_count, 0),
|
||||
};
|
||||
CD3DX12_ROOT_PARAMETER RP[2];
|
||||
RP[0].InitAsDescriptorTable((texture_count > 0) ? 3 : 2, &descriptorRange[0]);
|
||||
RP[1].InitAsDescriptorTable(1, &descriptorRange[3]);
|
||||
CD3DX12_DESCRIPTOR_RANGE descriptorRange[] =
|
||||
{
|
||||
// Vertex buffer
|
||||
CD3DX12_DESCRIPTOR_RANGE(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, vertex_buffer_count, 0),
|
||||
// Scale Offset data
|
||||
CD3DX12_DESCRIPTOR_RANGE(D3D12_DESCRIPTOR_RANGE_TYPE_CBV, 1, 0),
|
||||
// Constants
|
||||
CD3DX12_DESCRIPTOR_RANGE(D3D12_DESCRIPTOR_RANGE_TYPE_CBV, 2, 1),
|
||||
// Textures
|
||||
CD3DX12_DESCRIPTOR_RANGE(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, texture_count, 16),
|
||||
// Samplers
|
||||
CD3DX12_DESCRIPTOR_RANGE(D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, texture_count, 0),
|
||||
};
|
||||
CD3DX12_ROOT_PARAMETER RP[2];
|
||||
UINT cbv_srv_uav_descriptor_size = 4;
|
||||
if (texture_count == 0)
|
||||
cbv_srv_uav_descriptor_size -= 1;
|
||||
if (vertex_buffer_count == 0)
|
||||
cbv_srv_uav_descriptor_size -= 1;
|
||||
RP[0].InitAsDescriptorTable(cbv_srv_uav_descriptor_size, (vertex_buffer_count > 0) ? &descriptorRange[0] : &descriptorRange[1]);
|
||||
RP[1].InitAsDescriptorTable(1, &descriptorRange[4]);
|
||||
|
||||
Microsoft::WRL::ComPtr<ID3DBlob> rootSignatureBlob;
|
||||
Microsoft::WRL::ComPtr<ID3DBlob> errorBlob;
|
||||
CHECK_HRESULT(wrapD3D12SerializeRootSignature(
|
||||
&CD3DX12_ROOT_SIGNATURE_DESC((texture_count > 0) ? 2 : 1, RP, 0, 0, D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT),
|
||||
D3D_ROOT_SIGNATURE_VERSION_1, &rootSignatureBlob, &errorBlob));
|
||||
Microsoft::WRL::ComPtr<ID3DBlob> rootSignatureBlob;
|
||||
Microsoft::WRL::ComPtr<ID3DBlob> errorBlob;
|
||||
CHECK_HRESULT(wrapD3D12SerializeRootSignature(
|
||||
&CD3DX12_ROOT_SIGNATURE_DESC((texture_count > 0) ? 2 : 1, RP, 0, 0),
|
||||
D3D_ROOT_SIGNATURE_VERSION_1, &rootSignatureBlob, &errorBlob));
|
||||
|
||||
m_device->CreateRootSignature(0,
|
||||
rootSignatureBlob->GetBufferPointer(),
|
||||
rootSignatureBlob->GetBufferSize(),
|
||||
IID_PPV_ARGS(m_root_signatures[texture_count].GetAddressOf()));
|
||||
m_device->CreateRootSignature(0,
|
||||
rootSignatureBlob->GetBufferPointer(),
|
||||
rootSignatureBlob->GetBufferSize(),
|
||||
IID_PPV_ARGS(m_root_signatures[texture_count][vertex_buffer_count].GetAddressOf()));
|
||||
}
|
||||
}
|
||||
|
||||
m_per_frame_storage[0].init(m_device.Get());
|
||||
@@ -177,8 +179,8 @@ D3D12GSRender::D3D12GSRender()
|
||||
m_per_frame_storage[1].init(m_device.Get());
|
||||
m_per_frame_storage[1].reset();
|
||||
|
||||
initConvertShader();
|
||||
m_output_scaling_pass.Init(m_device.Get(), m_command_queue.Get());
|
||||
init_convert_shader();
|
||||
m_output_scaling_pass.init(m_device.Get(), m_command_queue.Get());
|
||||
|
||||
CHECK_HRESULT(
|
||||
m_device->CreateCommittedResource(
|
||||
@@ -194,6 +196,17 @@ D3D12GSRender::D3D12GSRender()
|
||||
m_readback_resources.init(m_device.Get(), 1024 * 1024 * 128, D3D12_HEAP_TYPE_READBACK, D3D12_RESOURCE_STATE_COPY_DEST);
|
||||
m_buffer_data.init(m_device.Get(), 1024 * 1024 * 896, D3D12_HEAP_TYPE_UPLOAD, D3D12_RESOURCE_STATE_GENERIC_READ);
|
||||
|
||||
CHECK_HRESULT(
|
||||
m_device->CreateCommittedResource(
|
||||
&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT),
|
||||
D3D12_HEAP_FLAG_NONE,
|
||||
&CD3DX12_RESOURCE_DESC::Buffer(1024 * 1024 * 16),
|
||||
D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER,
|
||||
nullptr,
|
||||
IID_PPV_ARGS(m_vertex_buffer_data.GetAddressOf())
|
||||
)
|
||||
);
|
||||
|
||||
if (rpcs3::config.rsx.d3d12.overlay.value())
|
||||
init_d2d_structures();
|
||||
}
|
||||
@@ -204,13 +217,12 @@ D3D12GSRender::~D3D12GSRender()
|
||||
|
||||
m_texture_cache.unprotect_all();
|
||||
|
||||
gfxHandler = [this](u32) { return false; };
|
||||
m_dummy_texture->Release();
|
||||
m_convertPSO->Release();
|
||||
m_convertRootSignature->Release();
|
||||
m_convert_pso->Release();
|
||||
m_convert_root_signature->Release();
|
||||
m_per_frame_storage[0].release();
|
||||
m_per_frame_storage[1].release();
|
||||
m_output_scaling_pass.Release();
|
||||
m_output_scaling_pass.release();
|
||||
|
||||
release_d2d_structures();
|
||||
}
|
||||
@@ -246,68 +258,93 @@ void D3D12GSRender::end()
|
||||
prepare_render_targets(get_current_resource_storage().command_list.Get());
|
||||
|
||||
std::chrono::time_point<std::chrono::system_clock> rtt_duration_end = std::chrono::system_clock::now();
|
||||
m_timers.m_prepare_rtt_duration += std::chrono::duration_cast<std::chrono::microseconds>(rtt_duration_end - rtt_duration_start).count();
|
||||
m_timers.prepare_rtt_duration += std::chrono::duration_cast<std::chrono::microseconds>(rtt_duration_end - rtt_duration_start).count();
|
||||
|
||||
std::chrono::time_point<std::chrono::system_clock> vertex_index_duration_start = std::chrono::system_clock::now();
|
||||
|
||||
size_t currentDescriptorIndex = get_current_resource_storage().descriptors_heap_index;
|
||||
|
||||
size_t vertex_count;
|
||||
bool indexed_draw;
|
||||
std::tie(indexed_draw, vertex_count) = upload_and_set_vertex_index_data(get_current_resource_storage().command_list.Get());
|
||||
std::vector<D3D12_SHADER_RESOURCE_VIEW_DESC> vertex_buffer_views;
|
||||
std::tie(indexed_draw, vertex_count, vertex_buffer_views) = upload_and_set_vertex_index_data(get_current_resource_storage().command_list.Get());
|
||||
|
||||
size_t vertex_buffer_count = vertex_buffer_views.size();
|
||||
|
||||
std::chrono::time_point<std::chrono::system_clock> vertex_index_duration_end = std::chrono::system_clock::now();
|
||||
m_timers.m_vertex_index_duration += std::chrono::duration_cast<std::chrono::microseconds>(vertex_index_duration_end - vertex_index_duration_start).count();
|
||||
m_timers.vertex_index_duration += std::chrono::duration_cast<std::chrono::microseconds>(vertex_index_duration_end - vertex_index_duration_start).count();
|
||||
|
||||
std::chrono::time_point<std::chrono::system_clock> program_load_start = std::chrono::system_clock::now();
|
||||
load_program();
|
||||
std::chrono::time_point<std::chrono::system_clock> program_load_end = std::chrono::system_clock::now();
|
||||
m_timers.m_program_load_duration += std::chrono::duration_cast<std::chrono::microseconds>(program_load_end - program_load_start).count();
|
||||
m_timers.program_load_duration += std::chrono::duration_cast<std::chrono::microseconds>(program_load_end - program_load_start).count();
|
||||
|
||||
get_current_resource_storage().command_list->SetGraphicsRootSignature(m_root_signatures[std::get<2>(m_current_pso)].Get());
|
||||
get_current_resource_storage().command_list->SetGraphicsRootSignature(m_root_signatures[std::get<2>(m_current_pso)][vertex_buffer_count].Get());
|
||||
get_current_resource_storage().command_list->OMSetStencilRef(rsx::method_registers[NV4097_SET_STENCIL_FUNC_REF]);
|
||||
|
||||
std::chrono::time_point<std::chrono::system_clock> constants_duration_start = std::chrono::system_clock::now();
|
||||
|
||||
size_t currentDescriptorIndex = get_current_resource_storage().descriptors_heap_index;
|
||||
INT offset = 0;
|
||||
for (const auto view : vertex_buffer_views)
|
||||
{
|
||||
m_device->CreateShaderResourceView(m_vertex_buffer_data.Get(), &view,
|
||||
CD3DX12_CPU_DESCRIPTOR_HANDLE(get_current_resource_storage().descriptors_heap->GetCPUDescriptorHandleForHeapStart())
|
||||
.Offset((INT)currentDescriptorIndex + offset++, m_descriptor_stride_srv_cbv_uav));
|
||||
}
|
||||
|
||||
// Constants
|
||||
upload_and_bind_scale_offset_matrix(currentDescriptorIndex);
|
||||
upload_and_bind_vertex_shader_constants(currentDescriptorIndex + 1);
|
||||
upload_and_bind_fragment_shader_constants(currentDescriptorIndex + 2);
|
||||
upload_and_bind_scale_offset_matrix(currentDescriptorIndex + vertex_buffer_count);
|
||||
upload_and_bind_vertex_shader_constants(currentDescriptorIndex + 1 + vertex_buffer_count);
|
||||
upload_and_bind_fragment_shader_constants(currentDescriptorIndex + 2 + vertex_buffer_count);
|
||||
|
||||
std::chrono::time_point<std::chrono::system_clock> constants_duration_end = std::chrono::system_clock::now();
|
||||
m_timers.m_constants_duration += std::chrono::duration_cast<std::chrono::microseconds>(constants_duration_end - constants_duration_start).count();
|
||||
m_timers.constants_duration += std::chrono::duration_cast<std::chrono::microseconds>(constants_duration_end - constants_duration_start).count();
|
||||
|
||||
get_current_resource_storage().command_list->SetPipelineState(std::get<0>(m_current_pso).Get());
|
||||
|
||||
std::chrono::time_point<std::chrono::system_clock> texture_duration_start = std::chrono::system_clock::now();
|
||||
if (std::get<2>(m_current_pso) > 0)
|
||||
size_t texture_count = std::get<2>(m_current_pso);
|
||||
if (texture_count > 0)
|
||||
{
|
||||
upload_and_bind_textures(get_current_resource_storage().command_list.Get(), currentDescriptorIndex + 3, std::get<2>(m_current_pso) > 0);
|
||||
upload_and_bind_textures(get_current_resource_storage().command_list.Get(), texture_count);
|
||||
|
||||
for (unsigned i = 0; i < texture_count; i++)
|
||||
{
|
||||
ID3D12Resource *tex_resource;
|
||||
D3D12_SHADER_RESOURCE_VIEW_DESC srv;
|
||||
std::tie(tex_resource, srv) = m_current_shader_resources[i];
|
||||
m_device->CreateShaderResourceView(tex_resource, &srv,
|
||||
CD3DX12_CPU_DESCRIPTOR_HANDLE(get_current_resource_storage().descriptors_heap->GetCPUDescriptorHandleForHeapStart())
|
||||
.Offset((INT)currentDescriptorIndex + 3 + (INT)vertex_buffer_count + (INT)i, m_descriptor_stride_srv_cbv_uav)
|
||||
);
|
||||
m_device->CreateSampler(&m_current_samplers[i],
|
||||
CD3DX12_CPU_DESCRIPTOR_HANDLE(get_current_resource_storage().sampler_descriptor_heap[get_current_resource_storage().sampler_descriptors_heap_index]->GetCPUDescriptorHandleForHeapStart())
|
||||
.Offset((UINT)get_current_resource_storage().current_sampler_index + (UINT)i, m_descriptor_stride_samplers));
|
||||
}
|
||||
|
||||
get_current_resource_storage().command_list->SetGraphicsRootDescriptorTable(0,
|
||||
CD3DX12_GPU_DESCRIPTOR_HANDLE(get_current_resource_storage().descriptors_heap->GetGPUDescriptorHandleForHeapStart())
|
||||
.Offset((INT)currentDescriptorIndex, g_descriptor_stride_srv_cbv_uav)
|
||||
.Offset((INT)currentDescriptorIndex, m_descriptor_stride_srv_cbv_uav)
|
||||
);
|
||||
get_current_resource_storage().command_list->SetGraphicsRootDescriptorTable(1,
|
||||
CD3DX12_GPU_DESCRIPTOR_HANDLE(get_current_resource_storage().sampler_descriptor_heap[get_current_resource_storage().sampler_descriptors_heap_index]->GetGPUDescriptorHandleForHeapStart())
|
||||
.Offset((INT)get_current_resource_storage().current_sampler_index, g_descriptor_stride_samplers)
|
||||
.Offset((INT)get_current_resource_storage().current_sampler_index, m_descriptor_stride_samplers)
|
||||
);
|
||||
|
||||
get_current_resource_storage().current_sampler_index += std::get<2>(m_current_pso);
|
||||
get_current_resource_storage().descriptors_heap_index += std::get<2>(m_current_pso) + 3;
|
||||
get_current_resource_storage().descriptors_heap_index += std::get<2>(m_current_pso) + 3 + vertex_buffer_count;
|
||||
}
|
||||
else
|
||||
{
|
||||
get_current_resource_storage().command_list->SetDescriptorHeaps(1, get_current_resource_storage().descriptors_heap.GetAddressOf());
|
||||
get_current_resource_storage().command_list->SetGraphicsRootDescriptorTable(0,
|
||||
CD3DX12_GPU_DESCRIPTOR_HANDLE(get_current_resource_storage().descriptors_heap->GetGPUDescriptorHandleForHeapStart())
|
||||
.Offset((INT)currentDescriptorIndex, g_descriptor_stride_srv_cbv_uav)
|
||||
.Offset((INT)currentDescriptorIndex, m_descriptor_stride_srv_cbv_uav)
|
||||
);
|
||||
get_current_resource_storage().descriptors_heap_index += 3;
|
||||
get_current_resource_storage().descriptors_heap_index += 3 + vertex_buffer_count;
|
||||
}
|
||||
|
||||
std::chrono::time_point<std::chrono::system_clock> texture_duration_end = std::chrono::system_clock::now();
|
||||
m_timers.m_texture_duration += std::chrono::duration_cast<std::chrono::microseconds>(texture_duration_end - texture_duration_start).count();
|
||||
m_timers.texture_duration += std::chrono::duration_cast<std::chrono::microseconds>(texture_duration_end - texture_duration_start).count();
|
||||
set_rtt_and_ds(get_current_resource_storage().command_list.Get());
|
||||
|
||||
int clip_w = rsx::method_registers[NV4097_SET_SURFACE_CLIP_HORIZONTAL] >> 16;
|
||||
@@ -334,8 +371,8 @@ void D3D12GSRender::end()
|
||||
get_current_resource_storage().command_list->DrawInstanced((UINT)vertex_count, 1, 0, 0);
|
||||
|
||||
std::chrono::time_point<std::chrono::system_clock> end_duration = std::chrono::system_clock::now();
|
||||
m_timers.m_draw_calls_duration += std::chrono::duration_cast<std::chrono::microseconds>(end_duration - start_duration).count();
|
||||
m_timers.m_draw_calls_count++;
|
||||
m_timers.draw_calls_duration += std::chrono::duration_cast<std::chrono::microseconds>(end_duration - start_duration).count();
|
||||
m_timers.draw_calls_count++;
|
||||
|
||||
if (rpcs3::config.rsx.d3d12.debug_output.value())
|
||||
{
|
||||
@@ -348,20 +385,20 @@ void D3D12GSRender::end()
|
||||
|
||||
namespace
|
||||
{
|
||||
bool is_flip_surface_in_global_memory(u32 color_target)
|
||||
bool is_flip_surface_in_global_memory(rsx::surface_target color_target)
|
||||
{
|
||||
switch (color_target)
|
||||
{
|
||||
case CELL_GCM_SURFACE_TARGET_0:
|
||||
case CELL_GCM_SURFACE_TARGET_1:
|
||||
case CELL_GCM_SURFACE_TARGET_MRT1:
|
||||
case CELL_GCM_SURFACE_TARGET_MRT2:
|
||||
case CELL_GCM_SURFACE_TARGET_MRT3:
|
||||
case rsx::surface_target::surface_a:
|
||||
case rsx::surface_target::surface_b:
|
||||
case rsx::surface_target::surfaces_a_b:
|
||||
case rsx::surface_target::surfaces_a_b_c:
|
||||
case rsx::surface_target::surfaces_a_b_c_d:
|
||||
return true;
|
||||
case CELL_GCM_SURFACE_TARGET_NONE:
|
||||
case rsx::surface_target::none:
|
||||
return false;
|
||||
}
|
||||
throw EXCEPTION("Wrong color_target (%u)", color_target);
|
||||
throw EXCEPTION("Wrong color_target");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -370,7 +407,7 @@ void D3D12GSRender::flip(int buffer)
|
||||
ID3D12Resource *resource_to_flip;
|
||||
float viewport_w, viewport_h;
|
||||
|
||||
if (!is_flip_surface_in_global_memory(rsx::method_registers[NV4097_SET_SURFACE_COLOR_TARGET]))
|
||||
if (!is_flip_surface_in_global_memory(rsx::to_surface_target(rsx::method_registers[NV4097_SET_SURFACE_COLOR_TARGET])))
|
||||
{
|
||||
resource_storage &storage = get_current_resource_storage();
|
||||
assert(storage.ram_framebuffer == nullptr);
|
||||
@@ -451,15 +488,15 @@ void D3D12GSRender::flip(int buffer)
|
||||
(LONG)m_backbuffer[m_swap_chain->GetCurrentBackBufferIndex()]->GetDesc().Height,
|
||||
};
|
||||
get_current_resource_storage().command_list->RSSetScissorRects(1, &box);
|
||||
get_current_resource_storage().command_list->SetGraphicsRootSignature(m_output_scaling_pass.m_rootSignature);
|
||||
get_current_resource_storage().command_list->SetPipelineState(m_output_scaling_pass.m_PSO);
|
||||
get_current_resource_storage().command_list->SetGraphicsRootSignature(m_output_scaling_pass.root_signature);
|
||||
get_current_resource_storage().command_list->SetPipelineState(m_output_scaling_pass.pso);
|
||||
|
||||
D3D12_SHADER_RESOURCE_VIEW_DESC shader_resource_view_desc = {};
|
||||
// FIXME: Not always true
|
||||
shader_resource_view_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
shader_resource_view_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
|
||||
shader_resource_view_desc.Texture2D.MipLevels = 1;
|
||||
if (is_flip_surface_in_global_memory(rsx::method_registers[NV4097_SET_SURFACE_COLOR_TARGET]))
|
||||
if (is_flip_surface_in_global_memory(rsx::to_surface_target(rsx::method_registers[NV4097_SET_SURFACE_COLOR_TARGET])))
|
||||
shader_resource_view_desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
|
||||
else
|
||||
shader_resource_view_desc.Shader4ComponentMapping = D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING(
|
||||
@@ -469,7 +506,7 @@ void D3D12GSRender::flip(int buffer)
|
||||
D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_0
|
||||
);
|
||||
m_device->CreateShaderResourceView(resource_to_flip, &shader_resource_view_desc,
|
||||
CD3DX12_CPU_DESCRIPTOR_HANDLE(m_output_scaling_pass.m_textureDescriptorHeap->GetCPUDescriptorHandleForHeapStart()).Offset(m_swap_chain->GetCurrentBackBufferIndex(), g_descriptor_stride_srv_cbv_uav));
|
||||
CD3DX12_CPU_DESCRIPTOR_HANDLE(m_output_scaling_pass.texture_descriptor_heap->GetCPUDescriptorHandleForHeapStart()).Offset(m_swap_chain->GetCurrentBackBufferIndex(), m_descriptor_stride_srv_cbv_uav));
|
||||
|
||||
D3D12_SAMPLER_DESC sampler_desc = {};
|
||||
sampler_desc.Filter = D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT;
|
||||
@@ -477,24 +514,24 @@ void D3D12GSRender::flip(int buffer)
|
||||
sampler_desc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
|
||||
sampler_desc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
|
||||
m_device->CreateSampler(&sampler_desc,
|
||||
CD3DX12_CPU_DESCRIPTOR_HANDLE(m_output_scaling_pass.m_samplerDescriptorHeap->GetCPUDescriptorHandleForHeapStart()).Offset(m_swap_chain->GetCurrentBackBufferIndex(), g_descriptor_stride_samplers));
|
||||
CD3DX12_CPU_DESCRIPTOR_HANDLE(m_output_scaling_pass.sampler_descriptor_heap->GetCPUDescriptorHandleForHeapStart()).Offset(m_swap_chain->GetCurrentBackBufferIndex(), m_descriptor_stride_samplers));
|
||||
|
||||
ID3D12DescriptorHeap *descriptors_heaps[] =
|
||||
{
|
||||
m_output_scaling_pass.m_textureDescriptorHeap,
|
||||
m_output_scaling_pass.m_samplerDescriptorHeap
|
||||
m_output_scaling_pass.texture_descriptor_heap,
|
||||
m_output_scaling_pass.sampler_descriptor_heap
|
||||
};
|
||||
get_current_resource_storage().command_list->SetDescriptorHeaps(2, descriptors_heaps);
|
||||
get_current_resource_storage().command_list->SetGraphicsRootDescriptorTable(0,
|
||||
CD3DX12_GPU_DESCRIPTOR_HANDLE(m_output_scaling_pass.m_textureDescriptorHeap->GetGPUDescriptorHandleForHeapStart()).Offset(m_swap_chain->GetCurrentBackBufferIndex(), g_descriptor_stride_srv_cbv_uav));
|
||||
CD3DX12_GPU_DESCRIPTOR_HANDLE(m_output_scaling_pass.texture_descriptor_heap->GetGPUDescriptorHandleForHeapStart()).Offset(m_swap_chain->GetCurrentBackBufferIndex(), m_descriptor_stride_srv_cbv_uav));
|
||||
get_current_resource_storage().command_list->SetGraphicsRootDescriptorTable(1,
|
||||
CD3DX12_GPU_DESCRIPTOR_HANDLE(m_output_scaling_pass.m_samplerDescriptorHeap->GetGPUDescriptorHandleForHeapStart()).Offset(m_swap_chain->GetCurrentBackBufferIndex(), g_descriptor_stride_samplers));
|
||||
CD3DX12_GPU_DESCRIPTOR_HANDLE(m_output_scaling_pass.sampler_descriptor_heap->GetGPUDescriptorHandleForHeapStart()).Offset(m_swap_chain->GetCurrentBackBufferIndex(), m_descriptor_stride_samplers));
|
||||
|
||||
get_current_resource_storage().command_list->OMSetRenderTargets(1,
|
||||
&CD3DX12_CPU_DESCRIPTOR_HANDLE(m_backbuffer_descriptor_heap[m_swap_chain->GetCurrentBackBufferIndex()]->GetCPUDescriptorHandleForHeapStart()),
|
||||
true, nullptr);
|
||||
D3D12_VERTEX_BUFFER_VIEW vertex_buffer_view = {};
|
||||
vertex_buffer_view.BufferLocation = m_output_scaling_pass.m_vertexBuffer->GetGPUVirtualAddress();
|
||||
vertex_buffer_view.BufferLocation = m_output_scaling_pass.vertex_buffer->GetGPUVirtualAddress();
|
||||
vertex_buffer_view.StrideInBytes = 4 * sizeof(float);
|
||||
vertex_buffer_view.SizeInBytes = 16 * sizeof(float);
|
||||
get_current_resource_storage().command_list->IASetVertexBuffers(0, 1, &vertex_buffer_view);
|
||||
@@ -504,7 +541,7 @@ void D3D12GSRender::flip(int buffer)
|
||||
|
||||
if (!rpcs3::config.rsx.d3d12.overlay.value())
|
||||
get_current_resource_storage().command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_backbuffer[m_swap_chain->GetCurrentBackBufferIndex()].Get(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT));
|
||||
if (is_flip_surface_in_global_memory(rsx::method_registers[NV4097_SET_SURFACE_COLOR_TARGET]) && resource_to_flip != nullptr)
|
||||
if (is_flip_surface_in_global_memory(rsx::to_surface_target(rsx::method_registers[NV4097_SET_SURFACE_COLOR_TARGET])) && resource_to_flip != nullptr)
|
||||
get_current_resource_storage().command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(resource_to_flip, D3D12_RESOURCE_STATE_GENERIC_READ, D3D12_RESOURCE_STATE_RENDER_TARGET));
|
||||
CHECK_HRESULT(get_current_resource_storage().command_list->Close());
|
||||
m_command_queue->ExecuteCommandLists(1, (ID3D12CommandList**)get_current_resource_storage().command_list.GetAddressOf());
|
||||
@@ -549,20 +586,36 @@ void D3D12GSRender::flip(int buffer)
|
||||
|
||||
|
||||
std::chrono::time_point<std::chrono::system_clock> flip_end = std::chrono::system_clock::now();
|
||||
m_timers.m_flip_duration += std::chrono::duration_cast<std::chrono::microseconds>(flip_end - flip_start).count();
|
||||
m_timers.flip_duration += std::chrono::duration_cast<std::chrono::microseconds>(flip_end - flip_start).count();
|
||||
}
|
||||
|
||||
bool D3D12GSRender::on_access_violation(u32 address, bool is_writing)
|
||||
{
|
||||
if (!is_writing)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (invalidate_address(address))
|
||||
{
|
||||
LOG_WARNING(RSX, "Reporting Cell writing to 0x%x", address);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void D3D12GSRender::reset_timer()
|
||||
{
|
||||
m_timers.m_draw_calls_count = 0;
|
||||
m_timers.m_draw_calls_duration = 0;
|
||||
m_timers.m_prepare_rtt_duration = 0;
|
||||
m_timers.m_vertex_index_duration = 0;
|
||||
m_timers.m_buffer_upload_size = 0;
|
||||
m_timers.m_program_load_duration = 0;
|
||||
m_timers.m_constants_duration = 0;
|
||||
m_timers.m_texture_duration = 0;
|
||||
m_timers.m_flip_duration = 0;
|
||||
m_timers.draw_calls_count = 0;
|
||||
m_timers.draw_calls_duration = 0;
|
||||
m_timers.prepare_rtt_duration = 0;
|
||||
m_timers.vertex_index_duration = 0;
|
||||
m_timers.buffer_upload_size = 0;
|
||||
m_timers.program_load_duration = 0;
|
||||
m_timers.constants_duration = 0;
|
||||
m_timers.texture_duration = 0;
|
||||
m_timers.flip_duration = 0;
|
||||
}
|
||||
|
||||
resource_storage& D3D12GSRender::get_current_resource_storage()
|
||||
|
||||
@@ -56,7 +56,7 @@ private:
|
||||
ComPtr<ID3D12Resource> m_backbuffer[2];
|
||||
ComPtr<ID3D12DescriptorHeap> m_backbuffer_descriptor_heap[2];
|
||||
// m_rootSignatures[N] is RS with N texture/sample
|
||||
ComPtr<ID3D12RootSignature> m_root_signatures[17];
|
||||
ComPtr<ID3D12RootSignature> m_root_signatures[17][17]; // indexed by [texture count][vertex count]
|
||||
|
||||
// TODO: Use a tree structure to parse more efficiently
|
||||
data_cache m_texture_cache;
|
||||
@@ -64,49 +64,49 @@ private:
|
||||
|
||||
rsx::surface_info m_surface;
|
||||
|
||||
RSXVertexProgram vertex_program;
|
||||
RSXFragmentProgram fragment_program;
|
||||
RSXVertexProgram m_vertex_program;
|
||||
RSXFragmentProgram m_fragment_program;
|
||||
PipelineStateObjectCache m_pso_cache;
|
||||
std::tuple<ComPtr<ID3D12PipelineState>, std::vector<size_t>, size_t> m_current_pso;
|
||||
std::tuple<ComPtr<ID3D12PipelineState>, size_t, size_t> m_current_pso;
|
||||
|
||||
struct
|
||||
{
|
||||
size_t m_draw_calls_duration;
|
||||
size_t m_draw_calls_count;
|
||||
size_t m_prepare_rtt_duration;
|
||||
size_t m_vertex_index_duration;
|
||||
size_t m_buffer_upload_size;
|
||||
size_t m_program_load_duration;
|
||||
size_t m_constants_duration;
|
||||
size_t m_texture_duration;
|
||||
size_t m_flip_duration;
|
||||
size_t draw_calls_duration;
|
||||
size_t draw_calls_count;
|
||||
size_t prepare_rtt_duration;
|
||||
size_t vertex_index_duration;
|
||||
size_t buffer_upload_size;
|
||||
size_t program_load_duration;
|
||||
size_t constants_duration;
|
||||
size_t texture_duration;
|
||||
size_t flip_duration;
|
||||
} m_timers;
|
||||
|
||||
void reset_timer();
|
||||
|
||||
struct Shader
|
||||
struct shader
|
||||
{
|
||||
ID3D12PipelineState *m_PSO;
|
||||
ID3D12RootSignature *m_rootSignature;
|
||||
ID3D12Resource *m_vertexBuffer;
|
||||
ID3D12DescriptorHeap *m_textureDescriptorHeap;
|
||||
ID3D12DescriptorHeap *m_samplerDescriptorHeap;
|
||||
void Init(ID3D12Device *device, ID3D12CommandQueue *gfxcommandqueue);
|
||||
void Release();
|
||||
ID3D12PipelineState *pso;
|
||||
ID3D12RootSignature *root_signature;
|
||||
ID3D12Resource *vertex_buffer;
|
||||
ID3D12DescriptorHeap *texture_descriptor_heap;
|
||||
ID3D12DescriptorHeap *sampler_descriptor_heap;
|
||||
void init(ID3D12Device *device, ID3D12CommandQueue *gfx_command_queue);
|
||||
void release();
|
||||
};
|
||||
|
||||
/**
|
||||
* Stores data related to the scaling pass that turns internal
|
||||
* render targets into presented buffers.
|
||||
*/
|
||||
Shader m_output_scaling_pass;
|
||||
shader m_output_scaling_pass;
|
||||
|
||||
/**
|
||||
* Data used when depth buffer is converted to uchar textures.
|
||||
*/
|
||||
ID3D12PipelineState *m_convertPSO;
|
||||
ID3D12RootSignature *m_convertRootSignature;
|
||||
void initConvertShader();
|
||||
ID3D12PipelineState *m_convert_pso;
|
||||
ID3D12RootSignature *m_convert_root_signature;
|
||||
void init_convert_shader();
|
||||
|
||||
resource_storage m_per_frame_storage[2];
|
||||
resource_storage &get_current_resource_storage();
|
||||
@@ -115,28 +115,25 @@ private:
|
||||
// Textures, constants, index and vertex buffers storage
|
||||
data_heap m_buffer_data;
|
||||
data_heap m_readback_resources;
|
||||
ComPtr<ID3D12Resource> m_vertex_buffer_data;
|
||||
|
||||
render_targets m_rtts;
|
||||
rsx::render_targets m_rtts;
|
||||
|
||||
std::vector<D3D12_INPUT_ELEMENT_DESC> m_IASet;
|
||||
|
||||
INT g_descriptor_stride_srv_cbv_uav;
|
||||
INT g_descriptor_stride_dsv;
|
||||
INT g_descriptor_stride_rtv;
|
||||
INT g_descriptor_stride_samplers;
|
||||
INT m_descriptor_stride_srv_cbv_uav;
|
||||
INT m_descriptor_stride_dsv;
|
||||
INT m_descriptor_stride_rtv;
|
||||
INT m_descriptor_stride_samplers;
|
||||
|
||||
// Used to fill unused texture slot
|
||||
ID3D12Resource *m_dummy_texture;
|
||||
|
||||
// Store previous fbo addresses to detect RTT config changes.
|
||||
std::array<u32, 4> m_previous_color_address = {};
|
||||
u32 m_previous_address_z = 0;
|
||||
u32 m_previous_target = 0;
|
||||
u32 m_previous_clip_horizontal = 0;
|
||||
u32 m_previous_clip_vertical = 0;
|
||||
// Currently used shader resources / samplers descriptor
|
||||
std::array<std::tuple<ID3D12Resource*, D3D12_SHADER_RESOURCE_VIEW_DESC>, 16> m_current_shader_resources = {};
|
||||
std::array<D3D12_SAMPLER_DESC, 16> m_current_samplers = {};
|
||||
public:
|
||||
D3D12GSRender();
|
||||
virtual ~D3D12GSRender();
|
||||
|
||||
private:
|
||||
void init_d2d_structures();
|
||||
void release_d2d_structures();
|
||||
@@ -150,16 +147,15 @@ private:
|
||||
* Non native primitive type are emulated by index buffers expansion.
|
||||
* Returns whether the draw call is indexed or not and the vertex count to draw.
|
||||
*/
|
||||
std::tuple<bool, size_t> upload_and_set_vertex_index_data(ID3D12GraphicsCommandList *command_list);
|
||||
std::tuple<bool, size_t, std::vector<D3D12_SHADER_RESOURCE_VIEW_DESC> > upload_and_set_vertex_index_data(ID3D12GraphicsCommandList *command_list);
|
||||
|
||||
/**
|
||||
* Upload all enabled vertex attributes for vertex in ranges described by vertex_ranges.
|
||||
* A range in vertex_range is a pair whose first element is the index of the beginning of the
|
||||
* range, and whose second element is the number of vertex in this range.
|
||||
*/
|
||||
std::vector<D3D12_VERTEX_BUFFER_VIEW> upload_vertex_attributes(const std::vector<std::pair<u32, u32> > &vertex_ranges);
|
||||
|
||||
std::tuple<D3D12_VERTEX_BUFFER_VIEW, size_t> upload_inlined_vertex_array();
|
||||
std::vector<D3D12_SHADER_RESOURCE_VIEW_DESC> upload_vertex_attributes(const std::vector<std::pair<u32, u32> > &vertex_ranges,
|
||||
gsl::not_null<ID3D12GraphicsCommandList*> command_list);
|
||||
|
||||
std::tuple<D3D12_INDEX_BUFFER_VIEW, size_t> generate_index_buffer_for_emulated_primitives_array(const std::vector<std::pair<u32, u32> > &vertex_ranges);
|
||||
|
||||
@@ -172,7 +168,7 @@ private:
|
||||
* Create necessary resource view/sampler descriptors in the per frame storage struct.
|
||||
* If the count of enabled texture is below texture_count, fills with dummy texture and sampler.
|
||||
*/
|
||||
void upload_and_bind_textures(ID3D12GraphicsCommandList *command_list, size_t descriptor_index, size_t texture_count);
|
||||
void upload_and_bind_textures(ID3D12GraphicsCommandList *command_list, size_t texture_count);
|
||||
|
||||
/**
|
||||
* Creates render target if necessary.
|
||||
@@ -200,8 +196,9 @@ protected:
|
||||
virtual void end() override;
|
||||
virtual void flip(int buffer) override;
|
||||
|
||||
virtual void copy_render_targets_to_memory(void *buffer, u8 rtt) override;
|
||||
virtual void copy_depth_buffer_to_memory(void *buffer) override;
|
||||
virtual void copy_stencil_buffer_to_memory(void *buffer) override;
|
||||
virtual bool on_access_violation(u32 address, bool is_writing) override;
|
||||
|
||||
virtual std::array<std::vector<gsl::byte>, 4> copy_render_targets_to_memory() override;
|
||||
virtual std::array<std::vector<gsl::byte>, 2> copy_depth_stencil_buffer_to_memory() override;
|
||||
virtual std::pair<std::string, std::string> get_programs() const override;
|
||||
};
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
#include "D3D12MemoryHelpers.h"
|
||||
|
||||
|
||||
void data_cache::store_and_protect_data(u64 key, u32 start, size_t size, u8 format, size_t w, size_t h, size_t m, ComPtr<ID3D12Resource> data)
|
||||
void data_cache::store_and_protect_data(u64 key, u32 start, size_t size, u8 format, size_t w, size_t h, size_t d, size_t m, ComPtr<ID3D12Resource> data)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mut);
|
||||
m_address_to_data[key] = std::make_pair(texture_entry(format, w, h, m), data);
|
||||
m_address_to_data[key] = std::make_pair(texture_entry(format, w, h, d, m), data);
|
||||
protect_data(key, start, size);
|
||||
}
|
||||
|
||||
@@ -106,7 +106,7 @@ void resource_storage::init(ID3D12Device *device)
|
||||
CHECK_HRESULT(m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, command_allocator.Get(), nullptr, IID_PPV_ARGS(command_list.GetAddressOf())));
|
||||
CHECK_HRESULT(command_list->Close());
|
||||
|
||||
D3D12_DESCRIPTOR_HEAP_DESC descriptor_heap_desc = { D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 10000, D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE };
|
||||
D3D12_DESCRIPTOR_HEAP_DESC descriptor_heap_desc = { D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 50000, D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE };
|
||||
CHECK_HRESULT(device->CreateDescriptorHeap(&descriptor_heap_desc, IID_PPV_ARGS(&descriptors_heap)));
|
||||
|
||||
D3D12_DESCRIPTOR_HEAP_DESC sampler_heap_desc = { D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER , 2048, D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE };
|
||||
|
||||
@@ -47,6 +47,11 @@ class data_heap
|
||||
size_t m_put_pos; // Start of free space
|
||||
ComPtr<ID3D12Resource> m_heap;
|
||||
public:
|
||||
data_heap() = default;
|
||||
~data_heap() = default;
|
||||
data_heap(const data_heap&) = delete;
|
||||
data_heap(data_heap&&) = delete;
|
||||
|
||||
size_t m_get_pos; // End of free space
|
||||
|
||||
template <typename... arg_type>
|
||||
@@ -134,16 +139,17 @@ struct texture_entry
|
||||
size_t m_width;
|
||||
size_t m_height;
|
||||
size_t m_mipmap;
|
||||
size_t m_depth;
|
||||
|
||||
texture_entry() : m_format(0), m_width(0), m_height(0), m_is_dirty(true)
|
||||
texture_entry() : m_format(0), m_width(0), m_height(0), m_depth(0), m_is_dirty(true)
|
||||
{}
|
||||
|
||||
texture_entry(u8 f, size_t w, size_t h, size_t m) : m_format(f), m_width(w), m_height(h), m_is_dirty(false)
|
||||
texture_entry(u8 f, size_t w, size_t h, size_t d, size_t m) : m_format(f), m_width(w), m_height(h), m_depth(d), m_is_dirty(false), m_mipmap(m)
|
||||
{}
|
||||
|
||||
bool operator==(const texture_entry &other)
|
||||
{
|
||||
return (m_format == other.m_format && m_width == other.m_width && m_height == other.m_height);
|
||||
return (m_format == other.m_format && m_width == other.m_width && m_height == other.m_height && m_mipmap == other.m_mipmap && m_depth == other.m_depth);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -163,7 +169,12 @@ private:
|
||||
std::unordered_map<u64, std::pair<texture_entry, ComPtr<ID3D12Resource>> > m_address_to_data; // Storage
|
||||
std::list <std::tuple<u64, u32, u32> > m_protected_ranges; // address, start of protected range, size of protected range
|
||||
public:
|
||||
void store_and_protect_data(u64 key, u32 start, size_t size, u8 format, size_t w, size_t h, size_t m, ComPtr<ID3D12Resource> data);
|
||||
data_cache() = default;
|
||||
~data_cache() = default;
|
||||
data_cache(const data_cache&) = delete;
|
||||
data_cache(data_cache&&) = delete;
|
||||
|
||||
void store_and_protect_data(u64 key, u32 start, size_t size, u8 format, size_t w, size_t h, size_t d, size_t m, ComPtr<ID3D12Resource> data);
|
||||
|
||||
/**
|
||||
* Make memory from start to start + size write protected.
|
||||
@@ -194,6 +205,11 @@ public:
|
||||
*/
|
||||
struct resource_storage
|
||||
{
|
||||
resource_storage() = default;
|
||||
~resource_storage() = default;
|
||||
resource_storage(const resource_storage&) = delete;
|
||||
resource_storage(resource_storage&&) = delete;
|
||||
|
||||
bool in_use; // False until command list has been populated at least once
|
||||
ComPtr<ID3D12Fence> frame_finished_fence;
|
||||
UINT64 fence_value;
|
||||
|
||||
@@ -152,21 +152,21 @@ void D3D12GSRender::release_d2d_structures()
|
||||
void D3D12GSRender::render_overlay()
|
||||
{
|
||||
D2D1_SIZE_F rtSize = g_d2d_render_targets[m_swap_chain->GetCurrentBackBufferIndex()]->GetSize();
|
||||
std::wstring duration = L"Draw duration : " + std::to_wstring(m_timers.m_draw_calls_duration) + L" us";
|
||||
float vtxIdxPercent = (float)m_timers.m_vertex_index_duration / (float)m_timers.m_draw_calls_duration;
|
||||
std::wstring vertexIndexDuration = L"Vtx/Idx upload : " + std::to_wstring(m_timers.m_vertex_index_duration) + L" us (" + std::to_wstring(100.f * vtxIdxPercent) + L" %)";
|
||||
std::wstring size = L"Upload size : " + std::to_wstring(m_timers.m_buffer_upload_size) + L" Bytes";
|
||||
float texPercent = (float)m_timers.m_texture_duration / (float)m_timers.m_draw_calls_duration;
|
||||
std::wstring texDuration = L"Textures : " + std::to_wstring(m_timers.m_texture_duration) + L" us (" + std::to_wstring(100.f * texPercent) + L" %)";
|
||||
float programPercent = (float)m_timers.m_program_load_duration / (float)m_timers.m_draw_calls_duration;
|
||||
std::wstring programDuration = L"Program : " + std::to_wstring(m_timers.m_program_load_duration) + L" us (" + std::to_wstring(100.f * programPercent) + L" %)";
|
||||
float constantsPercent = (float)m_timers.m_constants_duration / (float)m_timers.m_draw_calls_duration;
|
||||
std::wstring constantDuration = L"Constants : " + std::to_wstring(m_timers.m_constants_duration) + L" us (" + std::to_wstring(100.f * constantsPercent) + L" %)";
|
||||
float rttPercent = (float)m_timers.m_prepare_rtt_duration / (float)m_timers.m_draw_calls_duration;
|
||||
std::wstring rttDuration = L"RTT : " + std::to_wstring(m_timers.m_prepare_rtt_duration) + L" us (" + std::to_wstring(100.f * rttPercent) + L" %)";
|
||||
std::wstring flipDuration = L"Flip : " + std::to_wstring(m_timers.m_flip_duration) + L" us";
|
||||
std::wstring duration = L"Draw duration : " + std::to_wstring(m_timers.draw_calls_duration) + L" us";
|
||||
float vtxIdxPercent = (float)m_timers.vertex_index_duration / (float)m_timers.draw_calls_duration;
|
||||
std::wstring vertexIndexDuration = L"Vtx/Idx upload : " + std::to_wstring(m_timers.vertex_index_duration) + L" us (" + std::to_wstring(100.f * vtxIdxPercent) + L" %)";
|
||||
std::wstring size = L"Upload size : " + std::to_wstring(m_timers.buffer_upload_size) + L" Bytes";
|
||||
float texPercent = (float)m_timers.texture_duration / (float)m_timers.draw_calls_duration;
|
||||
std::wstring texDuration = L"Textures : " + std::to_wstring(m_timers.texture_duration) + L" us (" + std::to_wstring(100.f * texPercent) + L" %)";
|
||||
float programPercent = (float)m_timers.program_load_duration / (float)m_timers.draw_calls_duration;
|
||||
std::wstring programDuration = L"Program : " + std::to_wstring(m_timers.program_load_duration) + L" us (" + std::to_wstring(100.f * programPercent) + L" %)";
|
||||
float constantsPercent = (float)m_timers.constants_duration / (float)m_timers.draw_calls_duration;
|
||||
std::wstring constantDuration = L"Constants : " + std::to_wstring(m_timers.constants_duration) + L" us (" + std::to_wstring(100.f * constantsPercent) + L" %)";
|
||||
float rttPercent = (float)m_timers.prepare_rtt_duration / (float)m_timers.draw_calls_duration;
|
||||
std::wstring rttDuration = L"RTT : " + std::to_wstring(m_timers.prepare_rtt_duration) + L" us (" + std::to_wstring(100.f * rttPercent) + L" %)";
|
||||
std::wstring flipDuration = L"Flip : " + std::to_wstring(m_timers.flip_duration) + L" us";
|
||||
|
||||
std::wstring count = L"Draw count : " + std::to_wstring(m_timers.m_draw_calls_count);
|
||||
std::wstring count = L"Draw count : " + std::to_wstring(m_timers.draw_calls_count);
|
||||
draw_strings(rtSize, m_swap_chain->GetCurrentBackBufferIndex(),
|
||||
{
|
||||
duration,
|
||||
|
||||
@@ -38,36 +38,8 @@ void Shader::Compile(const std::string &code, SHADER_TYPE st)
|
||||
|
||||
void D3D12GSRender::load_program()
|
||||
{
|
||||
u32 transform_program_start = rsx::method_registers[NV4097_SET_TRANSFORM_PROGRAM_START];
|
||||
vertex_program.data.reserve((512 - transform_program_start) * 4);
|
||||
|
||||
for (int i = transform_program_start; i < 512; ++i)
|
||||
{
|
||||
vertex_program.data.resize((i - transform_program_start) * 4 + 4);
|
||||
memcpy(vertex_program.data.data() + (i - transform_program_start) * 4, transform_program + i * 4, 4 * sizeof(u32));
|
||||
|
||||
D3 d3;
|
||||
d3.HEX = transform_program[i * 4 + 3];
|
||||
|
||||
if (d3.end)
|
||||
break;
|
||||
}
|
||||
|
||||
u32 shader_program = rsx::method_registers[NV4097_SET_SHADER_PROGRAM];
|
||||
fragment_program.offset = shader_program & ~0x3;
|
||||
fragment_program.addr = rsx::get_address(fragment_program.offset, (shader_program & 0x3) - 1);
|
||||
fragment_program.ctrl = rsx::method_registers[NV4097_SET_SHADER_CONTROL];
|
||||
fragment_program.texture_dimensions.clear();
|
||||
|
||||
for (u32 i = 0; i < rsx::limits::textures_count; ++i)
|
||||
{
|
||||
if (!textures[i].enabled())
|
||||
fragment_program.texture_dimensions.push_back(texture_dimension::texture_dimension_2d);
|
||||
else if (textures[i].cubemap())
|
||||
fragment_program.texture_dimensions.push_back(texture_dimension::texture_dimension_cubemap);
|
||||
else
|
||||
fragment_program.texture_dimensions.push_back(texture_dimension::texture_dimension_2d);
|
||||
}
|
||||
m_vertex_program = get_current_vertex_program();
|
||||
m_fragment_program = get_current_fragment_program();
|
||||
|
||||
D3D12PipelineProperties prop = {};
|
||||
prop.Topology = get_primitive_topology_type(draw_mode);
|
||||
@@ -162,19 +134,19 @@ void D3D12GSRender::load_program()
|
||||
prop.DepthStencilFormat = get_depth_stencil_surface_format(m_surface.depth_format);
|
||||
prop.RenderTargetsFormat = get_color_surface_format(m_surface.color_format);
|
||||
|
||||
switch (u32 color_target = rsx::method_registers[NV4097_SET_SURFACE_COLOR_TARGET])
|
||||
switch (rsx::to_surface_target(rsx::method_registers[NV4097_SET_SURFACE_COLOR_TARGET]))
|
||||
{
|
||||
case CELL_GCM_SURFACE_TARGET_0:
|
||||
case CELL_GCM_SURFACE_TARGET_1:
|
||||
case rsx::surface_target::surface_a:
|
||||
case rsx::surface_target::surface_b:
|
||||
prop.numMRT = 1;
|
||||
break;
|
||||
case CELL_GCM_SURFACE_TARGET_MRT1:
|
||||
case rsx::surface_target::surfaces_a_b:
|
||||
prop.numMRT = 2;
|
||||
break;
|
||||
case CELL_GCM_SURFACE_TARGET_MRT2:
|
||||
case rsx::surface_target::surfaces_a_b_c:
|
||||
prop.numMRT = 3;
|
||||
break;
|
||||
case CELL_GCM_SURFACE_TARGET_MRT3:
|
||||
case rsx::surface_target::surfaces_a_b_c_d:
|
||||
prop.numMRT = 4;
|
||||
break;
|
||||
default:
|
||||
@@ -223,7 +195,7 @@ void D3D12GSRender::load_program()
|
||||
D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF,
|
||||
};
|
||||
prop.Rasterization = CD3D12_RASTERIZER_DESC;
|
||||
if (rsx::method_registers[NV4097_SET_CULL_FACE_ENABLE])
|
||||
if (!!rsx::method_registers[NV4097_SET_CULL_FACE_ENABLE])
|
||||
{
|
||||
switch (rsx::method_registers[NV4097_SET_CULL_FACE])
|
||||
{
|
||||
@@ -251,26 +223,25 @@ void D3D12GSRender::load_program()
|
||||
for (unsigned i = 0; i < prop.numMRT; i++)
|
||||
prop.Blend.RenderTarget[i].RenderTargetWriteMask = mask;
|
||||
|
||||
prop.IASet = m_IASet;
|
||||
if (!!rsx::method_registers[NV4097_SET_RESTART_INDEX_ENABLE])
|
||||
{
|
||||
Index_array_type index_type = to_index_array_type(rsx::method_registers[NV4097_SET_INDEX_ARRAY_DMA] >> 4);
|
||||
if (index_type == Index_array_type::unsigned_32b)
|
||||
rsx::index_array_type index_type = rsx::to_index_array_type(rsx::method_registers[NV4097_SET_INDEX_ARRAY_DMA] >> 4);
|
||||
if (index_type == rsx::index_array_type::u32)
|
||||
{
|
||||
prop.CutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFFFFFF;
|
||||
}
|
||||
if (index_type == Index_array_type::unsigned_16b)
|
||||
if (index_type == rsx::index_array_type::u16)
|
||||
{
|
||||
prop.CutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
m_current_pso = m_pso_cache.getGraphicPipelineState(vertex_program, fragment_program, prop, m_device.Get(), m_root_signatures);
|
||||
m_current_pso = m_pso_cache.getGraphicPipelineState(m_vertex_program, m_fragment_program, prop, m_device.Get(), m_root_signatures);
|
||||
return;
|
||||
}
|
||||
|
||||
std::pair<std::string, std::string> D3D12GSRender::get_programs() const
|
||||
{
|
||||
return std::make_pair(m_pso_cache.get_transform_program(vertex_program).content, m_pso_cache.get_shader_program(fragment_program).content);
|
||||
return std::make_pair(m_pso_cache.get_transform_program(m_vertex_program).content, m_pso_cache.get_shader_program(m_fragment_program).content);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -10,7 +10,6 @@ struct D3D12PipelineProperties
|
||||
D3D12_PRIMITIVE_TOPOLOGY_TYPE Topology;
|
||||
DXGI_FORMAT DepthStencilFormat;
|
||||
DXGI_FORMAT RenderTargetsFormat;
|
||||
std::vector<D3D12_INPUT_ELEMENT_DESC> IASet;
|
||||
D3D12_BLEND_DESC Blend;
|
||||
unsigned numMRT : 3;
|
||||
D3D12_DEPTH_STENCIL_DESC DepthStencil;
|
||||
@@ -19,23 +18,6 @@ struct D3D12PipelineProperties
|
||||
|
||||
bool operator==(const D3D12PipelineProperties &in) const
|
||||
{
|
||||
if (IASet.size() != in.IASet.size())
|
||||
return false;
|
||||
for (unsigned i = 0; i < IASet.size(); i++)
|
||||
{
|
||||
const D3D12_INPUT_ELEMENT_DESC &a = IASet[i], &b = in.IASet[i];
|
||||
if (a.AlignedByteOffset != b.AlignedByteOffset)
|
||||
return false;
|
||||
if (a.Format != b.Format)
|
||||
return false;
|
||||
if (a.InputSlot != b.InputSlot)
|
||||
return false;
|
||||
if (a.InstanceDataStepRate != b.InstanceDataStepRate)
|
||||
return false;
|
||||
if (a.SemanticIndex != b.SemanticIndex)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (memcmp(&DepthStencil, &in.DepthStencil, sizeof(D3D12_DEPTH_STENCIL_DESC)))
|
||||
return false;
|
||||
if (memcmp(&Blend, &in.Blend, sizeof(D3D12_BLEND_DESC)))
|
||||
@@ -93,7 +75,7 @@ public:
|
||||
ComPtr<ID3DBlob> bytecode;
|
||||
// For debugging
|
||||
std::string content;
|
||||
std::vector<size_t> vertex_shader_inputs;
|
||||
size_t vertex_shader_input_count;
|
||||
std::vector<size_t> FragmentConstantOffsetCache;
|
||||
size_t m_textureCount;
|
||||
|
||||
@@ -118,29 +100,11 @@ bool has_attribute(size_t attribute, const std::vector<D3D12_INPUT_ELEMENT_DESC>
|
||||
return false;
|
||||
}
|
||||
|
||||
static
|
||||
std::vector<D3D12_INPUT_ELEMENT_DESC> completes_IA_desc(const std::vector<D3D12_INPUT_ELEMENT_DESC> &desc, const std::vector<size_t> &inputs)
|
||||
{
|
||||
std::vector<D3D12_INPUT_ELEMENT_DESC> result(desc);
|
||||
for (size_t attribute : inputs)
|
||||
{
|
||||
if (has_attribute(attribute, desc))
|
||||
continue;
|
||||
D3D12_INPUT_ELEMENT_DESC extra_ia_desc = {};
|
||||
extra_ia_desc.SemanticIndex = (UINT)attribute;
|
||||
extra_ia_desc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
|
||||
extra_ia_desc.SemanticName = "TEXCOORD";
|
||||
extra_ia_desc.InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA;
|
||||
result.push_back(extra_ia_desc);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
struct D3D12Traits
|
||||
{
|
||||
using vertex_program_type = Shader;
|
||||
using fragment_program_type = Shader;
|
||||
using pipeline_storage_type = std::tuple<ComPtr<ID3D12PipelineState>, std::vector<size_t>, size_t>;
|
||||
using pipeline_storage_type = std::tuple<ComPtr<ID3D12PipelineState>, size_t, size_t>;
|
||||
using pipeline_properties = D3D12PipelineProperties;
|
||||
|
||||
static
|
||||
@@ -155,7 +119,7 @@ struct D3D12Traits
|
||||
{
|
||||
for (const ParamItem PI : PT.items)
|
||||
{
|
||||
if (PT.type == "sampler2D" || PT.type == "samplerCube")
|
||||
if (PT.type == "sampler1D" || PT.type == "sampler2D" || PT.type == "samplerCube" || PT.type == "sampler3D")
|
||||
{
|
||||
size_t texture_unit = atoi(PI.name.c_str() + 3);
|
||||
fragmentProgramData.m_textureCount = std::max(texture_unit + 1, fragmentProgramData.m_textureCount);
|
||||
@@ -176,15 +140,15 @@ struct D3D12Traits
|
||||
D3D12VertexProgramDecompiler VS(RSXVP);
|
||||
std::string shaderCode = VS.Decompile();
|
||||
vertexProgramData.Compile(shaderCode, Shader::SHADER_TYPE::SHADER_TYPE_VERTEX);
|
||||
vertexProgramData.vertex_shader_inputs = VS.input_slots;
|
||||
vertexProgramData.vertex_shader_input_count = RSXVP.rsx_vertex_inputs.size();
|
||||
fs::file(fs::get_config_dir() + "VertexProgram" + std::to_string(ID) + ".hlsl", fom::rewrite).write(shaderCode);
|
||||
vertexProgramData.id = (u32)ID;
|
||||
}
|
||||
|
||||
static
|
||||
pipeline_storage_type build_pipeline(
|
||||
const vertex_program_type &vertexProgramData, const fragment_program_type &fragmentProgramData, const pipeline_properties &pipelineProperties,
|
||||
ID3D12Device *device, gsl::span<ComPtr<ID3D12RootSignature>, 17> root_signatures)
|
||||
pipeline_storage_type build_pipeline(
|
||||
const vertex_program_type &vertexProgramData, const fragment_program_type &fragmentProgramData, const pipeline_properties &pipelineProperties,
|
||||
ID3D12Device *device, gsl::span<ComPtr<ID3D12RootSignature>, 17, 17> root_signatures)
|
||||
{
|
||||
std::tuple<ID3D12PipelineState *, std::vector<size_t>, size_t> result = {};
|
||||
D3D12_GRAPHICS_PIPELINE_STATE_DESC graphicPipelineStateDesc = {};
|
||||
@@ -199,7 +163,7 @@ struct D3D12Traits
|
||||
graphicPipelineStateDesc.PS.BytecodeLength = fragmentProgramData.bytecode->GetBufferSize();
|
||||
graphicPipelineStateDesc.PS.pShaderBytecode = fragmentProgramData.bytecode->GetBufferPointer();
|
||||
|
||||
graphicPipelineStateDesc.pRootSignature = root_signatures[fragmentProgramData.m_textureCount].Get();
|
||||
graphicPipelineStateDesc.pRootSignature = root_signatures[fragmentProgramData.m_textureCount][vertexProgramData.vertex_shader_input_count].Get();
|
||||
|
||||
graphicPipelineStateDesc.BlendState = pipelineProperties.Blend;
|
||||
graphicPipelineStateDesc.DepthStencilState = pipelineProperties.DepthStencil;
|
||||
@@ -211,10 +175,6 @@ struct D3D12Traits
|
||||
graphicPipelineStateDesc.RTVFormats[i] = pipelineProperties.RenderTargetsFormat;
|
||||
graphicPipelineStateDesc.DSVFormat = pipelineProperties.DepthStencilFormat;
|
||||
|
||||
const std::vector<D3D12_INPUT_ELEMENT_DESC> &completed_IA_desc = completes_IA_desc(pipelineProperties.IASet, vertexProgramData.vertex_shader_inputs);
|
||||
|
||||
graphicPipelineStateDesc.InputLayout.pInputElementDescs = completed_IA_desc.data();
|
||||
graphicPipelineStateDesc.InputLayout.NumElements = (UINT)completed_IA_desc.size();
|
||||
graphicPipelineStateDesc.SampleDesc.Count = 1;
|
||||
graphicPipelineStateDesc.SampleMask = UINT_MAX;
|
||||
graphicPipelineStateDesc.NodeMask = 1;
|
||||
@@ -226,7 +186,7 @@ struct D3D12Traits
|
||||
|
||||
std::wstring name = L"PSO_" + std::to_wstring(vertexProgramData.id) + L"_" + std::to_wstring(fragmentProgramData.id);
|
||||
pso->SetName(name.c_str());
|
||||
return std::make_tuple(pso, vertexProgramData.vertex_shader_inputs, fragmentProgramData.m_textureCount);
|
||||
return std::make_tuple(pso, vertexProgramData.vertex_shader_input_count, fragmentProgramData.m_textureCount);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -13,33 +13,42 @@
|
||||
#include "D3D12GSRender.h"
|
||||
#include "D3D12Formats.h"
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
UINT get_num_rtt(u8 color_target)
|
||||
u32 get_max_depth_value(rsx::surface_depth_format format)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case rsx::surface_depth_format::z16: return 0xFFFF;
|
||||
case rsx::surface_depth_format::z24s8: return 0xFFFFFF;
|
||||
}
|
||||
throw EXCEPTION("Unknow depth format");
|
||||
}
|
||||
|
||||
UINT get_num_rtt(rsx::surface_target color_target)
|
||||
{
|
||||
switch (color_target)
|
||||
{
|
||||
case CELL_GCM_SURFACE_TARGET_NONE: return 0;
|
||||
case CELL_GCM_SURFACE_TARGET_0:
|
||||
case CELL_GCM_SURFACE_TARGET_1: return 1;
|
||||
case CELL_GCM_SURFACE_TARGET_MRT1: return 2;
|
||||
case CELL_GCM_SURFACE_TARGET_MRT2: return 3;
|
||||
case CELL_GCM_SURFACE_TARGET_MRT3: return 4;
|
||||
case rsx::surface_target::none: return 0;
|
||||
case rsx::surface_target::surface_a:
|
||||
case rsx::surface_target::surface_b: return 1;
|
||||
case rsx::surface_target::surfaces_a_b: return 2;
|
||||
case rsx::surface_target::surfaces_a_b_c: return 3;
|
||||
case rsx::surface_target::surfaces_a_b_c_d: return 4;
|
||||
}
|
||||
throw EXCEPTION("Wrong color_target (%d)", color_target);
|
||||
}
|
||||
|
||||
std::vector<u8> get_rtt_indexes(u8 color_target)
|
||||
std::vector<u8> get_rtt_indexes(rsx::surface_target color_target)
|
||||
{
|
||||
switch (color_target)
|
||||
{
|
||||
case CELL_GCM_SURFACE_TARGET_NONE: return{};
|
||||
case CELL_GCM_SURFACE_TARGET_0: return{ 0 };
|
||||
case CELL_GCM_SURFACE_TARGET_1: return{ 1 };
|
||||
case CELL_GCM_SURFACE_TARGET_MRT1: return{ 0, 1 };
|
||||
case CELL_GCM_SURFACE_TARGET_MRT2: return{ 0, 1, 2 };
|
||||
case CELL_GCM_SURFACE_TARGET_MRT3: return{ 0, 1, 2, 3 };
|
||||
case rsx::surface_target::none: return{};
|
||||
case rsx::surface_target::surface_a: return{ 0 };
|
||||
case rsx::surface_target::surface_b: return{ 1 };
|
||||
case rsx::surface_target::surfaces_a_b: return{ 0, 1 };
|
||||
case rsx::surface_target::surfaces_a_b_c: return{ 0, 1, 2 };
|
||||
case rsx::surface_target::surfaces_a_b_c_d: return{ 0, 1, 2, 3 };
|
||||
}
|
||||
throw EXCEPTION("Wrong color_target (%d)", color_target);
|
||||
}
|
||||
@@ -63,6 +72,50 @@ namespace
|
||||
{
|
||||
return register_value & 0xff;
|
||||
}
|
||||
|
||||
size_t get_aligned_pitch(rsx::surface_color_format format, u32 width)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case rsx::surface_color_format::b8: return align(width, 256);
|
||||
case rsx::surface_color_format::g8b8:
|
||||
case rsx::surface_color_format::x1r5g5b5_o1r5g5b5:
|
||||
case rsx::surface_color_format::x1r5g5b5_z1r5g5b5:
|
||||
case rsx::surface_color_format::r5g6b5: return align(width * 2, 256);
|
||||
case rsx::surface_color_format::a8b8g8r8:
|
||||
case rsx::surface_color_format::x8b8g8r8_o8b8g8r8:
|
||||
case rsx::surface_color_format::x8b8g8r8_z8b8g8r8:
|
||||
case rsx::surface_color_format::x8r8g8b8_o8r8g8b8:
|
||||
case rsx::surface_color_format::x8r8g8b8_z8r8g8b8:
|
||||
case rsx::surface_color_format::x32:
|
||||
case rsx::surface_color_format::a8r8g8b8: return align(width * 4, 256);
|
||||
case rsx::surface_color_format::w16z16y16x16: return align(width * 8, 256);
|
||||
case rsx::surface_color_format::w32z32y32x32: return align(width * 16, 256);
|
||||
}
|
||||
throw EXCEPTION("Unknow color surface format");
|
||||
}
|
||||
|
||||
size_t get_packed_pitch(rsx::surface_color_format format, u32 width)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case rsx::surface_color_format::b8: return width;
|
||||
case rsx::surface_color_format::g8b8:
|
||||
case rsx::surface_color_format::x1r5g5b5_o1r5g5b5:
|
||||
case rsx::surface_color_format::x1r5g5b5_z1r5g5b5:
|
||||
case rsx::surface_color_format::r5g6b5: return width * 2;
|
||||
case rsx::surface_color_format::a8b8g8r8:
|
||||
case rsx::surface_color_format::x8b8g8r8_o8b8g8r8:
|
||||
case rsx::surface_color_format::x8b8g8r8_z8b8g8r8:
|
||||
case rsx::surface_color_format::x8r8g8b8_o8r8g8b8:
|
||||
case rsx::surface_color_format::x8r8g8b8_z8r8g8b8:
|
||||
case rsx::surface_color_format::x32:
|
||||
case rsx::surface_color_format::a8r8g8b8: return width * 4;
|
||||
case rsx::surface_color_format::w16z16y16x16: return width * 8;
|
||||
case rsx::surface_color_format::w32z32y32x32: return width * 16;
|
||||
}
|
||||
throw EXCEPTION("Unknow color surface format");
|
||||
}
|
||||
}
|
||||
|
||||
void D3D12GSRender::clear_surface(u32 arg)
|
||||
@@ -73,7 +126,7 @@ void D3D12GSRender::clear_surface(u32 arg)
|
||||
prepare_render_targets(get_current_resource_storage().command_list.Get());
|
||||
|
||||
std::chrono::time_point<std::chrono::system_clock> rtt_duration_end = std::chrono::system_clock::now();
|
||||
m_timers.m_prepare_rtt_duration += std::chrono::duration_cast<std::chrono::microseconds>(rtt_duration_end - rtt_duration_start).count();
|
||||
m_timers.prepare_rtt_duration += std::chrono::duration_cast<std::chrono::microseconds>(rtt_duration_end - rtt_duration_start).count();
|
||||
|
||||
if (arg & 0x1 || arg & 0x2)
|
||||
{
|
||||
@@ -82,7 +135,7 @@ void D3D12GSRender::clear_surface(u32 arg)
|
||||
if (arg & 0x1)
|
||||
{
|
||||
u32 clear_depth = rsx::method_registers[NV4097_SET_ZSTENCIL_CLEAR_VALUE] >> 8;
|
||||
u32 max_depth_value = m_surface.depth_format == CELL_GCM_SURFACE_Z16 ? 0x0000ffff : 0x00ffffff;
|
||||
u32 max_depth_value = get_max_depth_value(m_surface.depth_format);
|
||||
get_current_resource_storage().command_list->ClearDepthStencilView(m_rtts.current_ds_handle, D3D12_CLEAR_FLAG_DEPTH, clear_depth / (float)max_depth_value, 0,
|
||||
1, &get_scissor(rsx::method_registers[NV4097_SET_SCISSOR_HORIZONTAL], rsx::method_registers[NV4097_SET_SCISSOR_VERTICAL]));
|
||||
}
|
||||
@@ -95,16 +148,16 @@ void D3D12GSRender::clear_surface(u32 arg)
|
||||
if (arg & 0xF0)
|
||||
{
|
||||
CD3DX12_CPU_DESCRIPTOR_HANDLE handle = CD3DX12_CPU_DESCRIPTOR_HANDLE(m_rtts.current_rtts_handle);
|
||||
size_t rtt_index = get_num_rtt(rsx::method_registers[NV4097_SET_SURFACE_COLOR_TARGET]);
|
||||
size_t rtt_index = get_num_rtt(rsx::to_surface_target(rsx::method_registers[NV4097_SET_SURFACE_COLOR_TARGET]));
|
||||
get_current_resource_storage().render_targets_descriptors_heap_index += rtt_index;
|
||||
for (unsigned i = 0; i < rtt_index; i++)
|
||||
get_current_resource_storage().command_list->ClearRenderTargetView(handle.Offset(i, g_descriptor_stride_rtv), get_clear_color(rsx::method_registers[NV4097_SET_COLOR_CLEAR_VALUE]).data(),
|
||||
get_current_resource_storage().command_list->ClearRenderTargetView(handle.Offset(i, m_descriptor_stride_rtv), get_clear_color(rsx::method_registers[NV4097_SET_COLOR_CLEAR_VALUE]).data(),
|
||||
1, &get_scissor(rsx::method_registers[NV4097_SET_SCISSOR_HORIZONTAL], rsx::method_registers[NV4097_SET_SCISSOR_VERTICAL]));
|
||||
}
|
||||
|
||||
std::chrono::time_point<std::chrono::system_clock> end_duration = std::chrono::system_clock::now();
|
||||
m_timers.m_draw_calls_duration += std::chrono::duration_cast<std::chrono::microseconds>(end_duration - start_duration).count();
|
||||
m_timers.m_draw_calls_count++;
|
||||
m_timers.draw_calls_duration += std::chrono::duration_cast<std::chrono::microseconds>(end_duration - start_duration).count();
|
||||
m_timers.draw_calls_count++;
|
||||
|
||||
if (rpcs3::config.rsx.d3d12.debug_output.value())
|
||||
{
|
||||
@@ -118,58 +171,23 @@ void D3D12GSRender::prepare_render_targets(ID3D12GraphicsCommandList *copycmdlis
|
||||
{
|
||||
// check if something has changed
|
||||
u32 surface_format = rsx::method_registers[NV4097_SET_SURFACE_FORMAT];
|
||||
u32 context_dma_color[] =
|
||||
{
|
||||
rsx::method_registers[NV4097_SET_CONTEXT_DMA_COLOR_A],
|
||||
rsx::method_registers[NV4097_SET_CONTEXT_DMA_COLOR_B],
|
||||
rsx::method_registers[NV4097_SET_CONTEXT_DMA_COLOR_C],
|
||||
rsx::method_registers[NV4097_SET_CONTEXT_DMA_COLOR_D]
|
||||
};
|
||||
u32 m_context_dma_z = rsx::method_registers[NV4097_SET_CONTEXT_DMA_ZETA];
|
||||
|
||||
u32 offset_color[] =
|
||||
{
|
||||
rsx::method_registers[NV4097_SET_SURFACE_COLOR_AOFFSET],
|
||||
rsx::method_registers[NV4097_SET_SURFACE_COLOR_BOFFSET],
|
||||
rsx::method_registers[NV4097_SET_SURFACE_COLOR_COFFSET],
|
||||
rsx::method_registers[NV4097_SET_SURFACE_COLOR_DOFFSET]
|
||||
};
|
||||
u32 offset_zeta = rsx::method_registers[NV4097_SET_SURFACE_ZETA_OFFSET];
|
||||
|
||||
// FBO location has changed, previous data might be copied
|
||||
std::array<u32, 4> address_color =
|
||||
{
|
||||
rsx::get_address(offset_color[0], context_dma_color[0]),
|
||||
rsx::get_address(offset_color[1], context_dma_color[1]),
|
||||
rsx::get_address(offset_color[2], context_dma_color[2]),
|
||||
rsx::get_address(offset_color[3], context_dma_color[3]),
|
||||
};
|
||||
u32 address_z = rsx::get_address(offset_zeta, m_context_dma_z);
|
||||
|
||||
u32 clip_h_reg = rsx::method_registers[NV4097_SET_SURFACE_CLIP_HORIZONTAL];
|
||||
u32 clip_v_reg = rsx::method_registers[NV4097_SET_SURFACE_CLIP_VERTICAL];
|
||||
u32 target_reg = rsx::method_registers[NV4097_SET_SURFACE_COLOR_TARGET];
|
||||
|
||||
// Exit early if there is no rtt changes
|
||||
if (m_previous_color_address == address_color &&
|
||||
m_previous_address_z == address_z &&
|
||||
m_surface.format == surface_format &&
|
||||
m_previous_clip_horizontal == clip_h_reg &&
|
||||
m_previous_clip_vertical == clip_v_reg &&
|
||||
m_previous_target == target_reg)
|
||||
if (!m_rtts_dirty)
|
||||
return;
|
||||
m_rtts_dirty = false;
|
||||
|
||||
m_previous_color_address = address_color;
|
||||
m_previous_address_z = address_z;
|
||||
m_previous_target = target_reg;
|
||||
m_previous_clip_horizontal = clip_h_reg;
|
||||
m_previous_clip_vertical = clip_v_reg;
|
||||
|
||||
if (m_surface.format != surface_format)
|
||||
m_surface.unpack(surface_format);
|
||||
|
||||
std::array<float, 4> clear_color = get_clear_color(rsx::method_registers[NV4097_SET_COLOR_CLEAR_VALUE]);
|
||||
m_rtts.prepare_render_target(copycmdlist, surface_format, clip_h_reg, clip_v_reg, target_reg, address_color, address_z, m_device.Get(), clear_color, 1.f, 0);
|
||||
m_rtts.prepare_render_target(copycmdlist,
|
||||
rsx::method_registers[NV4097_SET_SURFACE_FORMAT],
|
||||
rsx::method_registers[NV4097_SET_SURFACE_CLIP_HORIZONTAL], rsx::method_registers[NV4097_SET_SURFACE_CLIP_VERTICAL],
|
||||
rsx::to_surface_target(rsx::method_registers[NV4097_SET_SURFACE_COLOR_TARGET]),
|
||||
get_color_surface_addresses(), get_zeta_surface_address(),
|
||||
m_device.Get(), clear_color, 1.f, 0);
|
||||
|
||||
// write descriptors
|
||||
DXGI_FORMAT dxgi_format = get_color_surface_format(m_surface.color_format);
|
||||
@@ -178,14 +196,14 @@ void D3D12GSRender::prepare_render_targets(ID3D12GraphicsCommandList *copycmdlis
|
||||
rtt_view_desc.Format = dxgi_format;
|
||||
|
||||
m_rtts.current_rtts_handle = CD3DX12_CPU_DESCRIPTOR_HANDLE(get_current_resource_storage().render_targets_descriptors_heap->GetCPUDescriptorHandleForHeapStart())
|
||||
.Offset((INT)get_current_resource_storage().render_targets_descriptors_heap_index * g_descriptor_stride_rtv);
|
||||
.Offset((INT)get_current_resource_storage().render_targets_descriptors_heap_index * m_descriptor_stride_rtv);
|
||||
size_t rtt_index = 0;
|
||||
for (u8 i : get_rtt_indexes(rsx::method_registers[NV4097_SET_SURFACE_COLOR_TARGET]))
|
||||
for (u8 i : get_rtt_indexes(rsx::to_surface_target(rsx::method_registers[NV4097_SET_SURFACE_COLOR_TARGET])))
|
||||
{
|
||||
if (std::get<1>(m_rtts.m_bound_render_targets[i]) == nullptr)
|
||||
continue;
|
||||
m_device->CreateRenderTargetView(std::get<1>(m_rtts.m_bound_render_targets[i]), &rtt_view_desc,
|
||||
CD3DX12_CPU_DESCRIPTOR_HANDLE(m_rtts.current_rtts_handle).Offset((INT)rtt_index * g_descriptor_stride_rtv));
|
||||
CD3DX12_CPU_DESCRIPTOR_HANDLE(m_rtts.current_rtts_handle).Offset((INT)rtt_index * m_descriptor_stride_rtv));
|
||||
rtt_index++;
|
||||
}
|
||||
get_current_resource_storage().render_targets_descriptors_heap_index += rtt_index;
|
||||
@@ -193,7 +211,7 @@ void D3D12GSRender::prepare_render_targets(ID3D12GraphicsCommandList *copycmdlis
|
||||
if (std::get<1>(m_rtts.m_bound_depth_stencil) == nullptr)
|
||||
return;
|
||||
m_rtts.current_ds_handle = CD3DX12_CPU_DESCRIPTOR_HANDLE(get_current_resource_storage().depth_stencil_descriptor_heap->GetCPUDescriptorHandleForHeapStart())
|
||||
.Offset((INT)get_current_resource_storage().depth_stencil_descriptor_heap_index * g_descriptor_stride_rtv);
|
||||
.Offset((INT)get_current_resource_storage().depth_stencil_descriptor_heap_index * m_descriptor_stride_dsv);
|
||||
get_current_resource_storage().depth_stencil_descriptor_heap_index += 1;
|
||||
D3D12_DEPTH_STENCIL_VIEW_DESC depth_stencil_view_desc = {};
|
||||
depth_stencil_view_desc.Format = get_depth_stencil_surface_format(m_surface.depth_format);
|
||||
@@ -203,13 +221,12 @@ void D3D12GSRender::prepare_render_targets(ID3D12GraphicsCommandList *copycmdlis
|
||||
|
||||
void D3D12GSRender::set_rtt_and_ds(ID3D12GraphicsCommandList *command_list)
|
||||
{
|
||||
UINT num_rtt = get_num_rtt(rsx::method_registers[NV4097_SET_SURFACE_COLOR_TARGET]);
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE* rtt_handle = (num_rtt > 0) ? &m_rtts.current_rtts_handle : nullptr;
|
||||
UINT num_rtt = get_num_rtt(rsx::to_surface_target(rsx::method_registers[NV4097_SET_SURFACE_COLOR_TARGET]));
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE* ds_handle = (std::get<1>(m_rtts.m_bound_depth_stencil) != nullptr) ? &m_rtts.current_ds_handle : nullptr;
|
||||
command_list->OMSetRenderTargets((UINT)num_rtt, rtt_handle, true, ds_handle);
|
||||
command_list->OMSetRenderTargets((UINT)num_rtt, &m_rtts.current_rtts_handle, true, ds_handle);
|
||||
}
|
||||
|
||||
void render_targets::init(ID3D12Device *device)
|
||||
void rsx::render_targets::init(ID3D12Device *device)
|
||||
{
|
||||
g_descriptor_stride_rtv = device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
|
||||
}
|
||||
@@ -225,26 +242,14 @@ namespace
|
||||
ID3D12GraphicsCommandList * command_list,
|
||||
data_heap &readback_heap,
|
||||
ID3D12Resource * color_surface,
|
||||
int color_surface_format
|
||||
rsx::surface_color_format color_surface_format
|
||||
)
|
||||
{
|
||||
int clip_w = rsx::method_registers[NV4097_SET_SURFACE_CLIP_HORIZONTAL] >> 16;
|
||||
int clip_h = rsx::method_registers[NV4097_SET_SURFACE_CLIP_VERTICAL] >> 16;
|
||||
|
||||
DXGI_FORMAT dxgi_format = get_color_surface_format(color_surface_format);
|
||||
size_t row_pitch;
|
||||
switch (color_surface_format)
|
||||
{
|
||||
case CELL_GCM_SURFACE_R5G6B5:
|
||||
row_pitch = align(clip_w * 2, 256);
|
||||
break;
|
||||
case CELL_GCM_SURFACE_A8R8G8B8:
|
||||
row_pitch = align(clip_w * 4, 256);
|
||||
break;
|
||||
case CELL_GCM_SURFACE_F_W16Z16Y16X16:
|
||||
row_pitch = align(clip_w * 8, 256);
|
||||
break;
|
||||
}
|
||||
size_t row_pitch = get_aligned_pitch(color_surface_format, clip_w);
|
||||
|
||||
size_t buffer_size = row_pitch * clip_h;
|
||||
size_t heap_offset = readback_heap.alloc<D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT>(buffer_size);
|
||||
@@ -283,6 +288,8 @@ namespace
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void D3D12GSRender::copy_render_target_to_dma_location()
|
||||
{
|
||||
// Add all buffer write
|
||||
@@ -355,13 +362,13 @@ void D3D12GSRender::copy_render_target_to_dma_location()
|
||||
uav_desc.Format = DXGI_FORMAT_R8_UNORM;
|
||||
uav_desc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D;
|
||||
m_device->CreateUnorderedAccessView(depth_format_conversion_buffer.Get(), nullptr, &uav_desc,
|
||||
CD3DX12_CPU_DESCRIPTOR_HANDLE(descriptor_heap->GetCPUDescriptorHandleForHeapStart()).Offset(1, g_descriptor_stride_srv_cbv_uav));
|
||||
CD3DX12_CPU_DESCRIPTOR_HANDLE(descriptor_heap->GetCPUDescriptorHandleForHeapStart()).Offset(1, m_descriptor_stride_srv_cbv_uav));
|
||||
|
||||
// Convert
|
||||
get_current_resource_storage().command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(std::get<1>(m_rtts.m_bound_depth_stencil), D3D12_RESOURCE_STATE_DEPTH_WRITE, D3D12_RESOURCE_STATE_GENERIC_READ));
|
||||
|
||||
get_current_resource_storage().command_list->SetPipelineState(m_convertPSO);
|
||||
get_current_resource_storage().command_list->SetComputeRootSignature(m_convertRootSignature);
|
||||
get_current_resource_storage().command_list->SetPipelineState(m_convert_pso);
|
||||
get_current_resource_storage().command_list->SetComputeRootSignature(m_convert_root_signature);
|
||||
get_current_resource_storage().command_list->SetDescriptorHeaps(1, descriptor_heap.GetAddressOf());
|
||||
get_current_resource_storage().command_list->SetComputeRootDescriptorTable(0, descriptor_heap->GetGPUDescriptorHandleForHeapStart());
|
||||
get_current_resource_storage().command_list->Dispatch(clip_w / 8, clip_h / 8, 1);
|
||||
@@ -384,7 +391,7 @@ void D3D12GSRender::copy_render_target_to_dma_location()
|
||||
size_t color_buffer_offset_in_heap[4];
|
||||
if (rpcs3::state.config.rsx.opengl.write_color_buffers)
|
||||
{
|
||||
for (u8 i : get_rtt_indexes(rsx::method_registers[NV4097_SET_SURFACE_COLOR_TARGET]))
|
||||
for (u8 i : get_rtt_indexes(rsx::to_surface_target(rsx::method_registers[NV4097_SET_SURFACE_COLOR_TARGET])))
|
||||
{
|
||||
if (!address_color[i])
|
||||
continue;
|
||||
@@ -423,25 +430,11 @@ void D3D12GSRender::copy_render_target_to_dma_location()
|
||||
m_readback_resources.unmap();
|
||||
}
|
||||
|
||||
size_t srcPitch, dstPitch;
|
||||
switch (m_surface.color_format)
|
||||
{
|
||||
case CELL_GCM_SURFACE_R5G6B5:
|
||||
srcPitch = align(clip_w * 2, 256);
|
||||
dstPitch = clip_w * 2;
|
||||
break;
|
||||
case CELL_GCM_SURFACE_A8R8G8B8:
|
||||
srcPitch = align(clip_w * 4, 256);
|
||||
dstPitch = clip_w * 4;
|
||||
break;
|
||||
case CELL_GCM_SURFACE_F_W16Z16Y16X16:
|
||||
srcPitch = align(clip_w * 8, 256);
|
||||
dstPitch = clip_w * 8;
|
||||
break;
|
||||
}
|
||||
|
||||
if (rpcs3::state.config.rsx.opengl.write_color_buffers)
|
||||
{
|
||||
size_t srcPitch = get_aligned_pitch(m_surface.color_format, clip_w);
|
||||
size_t dstPitch = get_packed_pitch(m_surface.color_format, clip_w);
|
||||
|
||||
void *dest_buffer[] =
|
||||
{
|
||||
vm::base(address_color[0]),
|
||||
@@ -450,7 +443,7 @@ void D3D12GSRender::copy_render_target_to_dma_location()
|
||||
vm::base(address_color[3]),
|
||||
};
|
||||
|
||||
for (u8 i : get_rtt_indexes(rsx::method_registers[NV4097_SET_SURFACE_COLOR_TARGET]))
|
||||
for (u8 i : get_rtt_indexes(rsx::to_surface_target(rsx::method_registers[NV4097_SET_SURFACE_COLOR_TARGET])))
|
||||
{
|
||||
if (!address_color[i])
|
||||
continue;
|
||||
@@ -460,105 +453,21 @@ void D3D12GSRender::copy_render_target_to_dma_location()
|
||||
}
|
||||
|
||||
|
||||
void D3D12GSRender::copy_render_targets_to_memory(void *buffer, u8 rtt)
|
||||
std::array<std::vector<gsl::byte>, 4> D3D12GSRender::copy_render_targets_to_memory()
|
||||
{
|
||||
size_t heap_offset = download_to_readback_buffer(m_device.Get(), get_current_resource_storage().command_list.Get(), m_readback_resources, std::get<1>(m_rtts.m_bound_render_targets[rtt]), m_surface.color_format);
|
||||
|
||||
CHECK_HRESULT(get_current_resource_storage().command_list->Close());
|
||||
m_command_queue->ExecuteCommandLists(1, (ID3D12CommandList**)get_current_resource_storage().command_list.GetAddressOf());
|
||||
get_current_resource_storage().set_new_command_list();
|
||||
|
||||
wait_for_command_queue(m_device.Get(), m_command_queue.Get());
|
||||
m_readback_resources.m_get_pos = m_readback_resources.get_current_put_pos_minus_one();
|
||||
|
||||
int clip_w = rsx::method_registers[NV4097_SET_SURFACE_CLIP_HORIZONTAL] >> 16;
|
||||
int clip_h = rsx::method_registers[NV4097_SET_SURFACE_CLIP_VERTICAL] >> 16;
|
||||
size_t srcPitch, dstPitch;
|
||||
switch (m_surface.color_format)
|
||||
{
|
||||
case CELL_GCM_SURFACE_R5G6B5:
|
||||
srcPitch = align(clip_w * 2, 256);
|
||||
dstPitch = clip_w * 2;
|
||||
break;
|
||||
case CELL_GCM_SURFACE_A8R8G8B8:
|
||||
srcPitch = align(clip_w * 4, 256);
|
||||
dstPitch = clip_w * 4;
|
||||
break;
|
||||
case CELL_GCM_SURFACE_F_W16Z16Y16X16:
|
||||
srcPitch = align(clip_w * 8, 256);
|
||||
dstPitch = clip_w * 8;
|
||||
break;
|
||||
}
|
||||
copy_readback_buffer_to_dest(buffer, m_readback_resources, heap_offset, srcPitch, dstPitch, clip_h);
|
||||
rsx::surface_info surface = {};
|
||||
surface.unpack(rsx::method_registers[NV4097_SET_SURFACE_FORMAT]);
|
||||
return m_rtts.get_render_targets_data(surface.color_format, clip_w, clip_h, m_device.Get(), m_command_queue.Get(), m_readback_resources, get_current_resource_storage());
|
||||
}
|
||||
|
||||
void D3D12GSRender::copy_depth_buffer_to_memory(void *buffer)
|
||||
std::array<std::vector<gsl::byte>, 2> D3D12GSRender::copy_depth_stencil_buffer_to_memory()
|
||||
{
|
||||
unsigned clip_w = rsx::method_registers[NV4097_SET_SURFACE_CLIP_HORIZONTAL] >> 16;
|
||||
unsigned clip_h = rsx::method_registers[NV4097_SET_SURFACE_CLIP_VERTICAL] >> 16;
|
||||
|
||||
size_t row_pitch = align(clip_w * 4, 256);
|
||||
|
||||
size_t buffer_size = row_pitch * clip_h;
|
||||
size_t heap_offset = m_readback_resources.alloc<D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT>(buffer_size);
|
||||
|
||||
get_current_resource_storage().command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(std::get<1>(m_rtts.m_bound_depth_stencil), D3D12_RESOURCE_STATE_DEPTH_WRITE, D3D12_RESOURCE_STATE_COPY_SOURCE));
|
||||
|
||||
get_current_resource_storage().command_list->CopyTextureRegion(&CD3DX12_TEXTURE_COPY_LOCATION(m_readback_resources.get_heap(), { heap_offset,{ DXGI_FORMAT_R32_TYPELESS, (UINT)clip_w, (UINT)clip_h, 1, (UINT)row_pitch } }), 0, 0, 0,
|
||||
&CD3DX12_TEXTURE_COPY_LOCATION(std::get<1>(m_rtts.m_bound_depth_stencil), 0), nullptr);
|
||||
get_current_resource_storage().command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(std::get<1>(m_rtts.m_bound_depth_stencil), D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_DEPTH_WRITE));
|
||||
|
||||
CHECK_HRESULT(get_current_resource_storage().command_list->Close());
|
||||
m_command_queue->ExecuteCommandLists(1, (ID3D12CommandList**)get_current_resource_storage().command_list.GetAddressOf());
|
||||
get_current_resource_storage().set_new_command_list();
|
||||
|
||||
wait_for_command_queue(m_device.Get(), m_command_queue.Get());
|
||||
m_readback_resources.m_get_pos = m_readback_resources.get_current_put_pos_minus_one();
|
||||
|
||||
void *mapped_buffer = m_readback_resources.map<void>(heap_offset);
|
||||
for (unsigned row = 0; row < clip_h; row++)
|
||||
{
|
||||
u32 *casted_dest = (u32*)((char*)buffer + row * clip_w * 4);
|
||||
u32 *casted_src = (u32*)((char*)mapped_buffer + row * row_pitch);
|
||||
for (unsigned col = 0; col < row_pitch / 4; col++)
|
||||
*casted_dest++ = *casted_src++;
|
||||
}
|
||||
m_readback_resources.unmap();
|
||||
int clip_w = rsx::method_registers[NV4097_SET_SURFACE_CLIP_HORIZONTAL] >> 16;
|
||||
int clip_h = rsx::method_registers[NV4097_SET_SURFACE_CLIP_VERTICAL] >> 16;
|
||||
rsx::surface_info surface = {};
|
||||
surface.unpack(rsx::method_registers[NV4097_SET_SURFACE_FORMAT]);
|
||||
return m_rtts.get_depth_stencil_data(surface.depth_format, clip_w, clip_h, m_device.Get(), m_command_queue.Get(), m_readback_resources, get_current_resource_storage());
|
||||
}
|
||||
|
||||
|
||||
void D3D12GSRender::copy_stencil_buffer_to_memory(void *buffer)
|
||||
{
|
||||
unsigned clip_w = rsx::method_registers[NV4097_SET_SURFACE_CLIP_HORIZONTAL] >> 16;
|
||||
unsigned clip_h = rsx::method_registers[NV4097_SET_SURFACE_CLIP_VERTICAL] >> 16;
|
||||
|
||||
size_t row_pitch = align(clip_w * 4, 256);
|
||||
|
||||
size_t buffer_size = row_pitch * clip_h;
|
||||
size_t heap_offset = m_readback_resources.alloc<D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT>(buffer_size);
|
||||
|
||||
get_current_resource_storage().command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(std::get<1>(m_rtts.m_bound_depth_stencil), D3D12_RESOURCE_STATE_DEPTH_WRITE, D3D12_RESOURCE_STATE_COPY_SOURCE));
|
||||
|
||||
get_current_resource_storage().command_list->CopyTextureRegion(&CD3DX12_TEXTURE_COPY_LOCATION(m_readback_resources.get_heap(), { heap_offset, { DXGI_FORMAT_R8_TYPELESS, (UINT)clip_w, (UINT)clip_h, 1, (UINT)row_pitch } }), 0, 0, 0,
|
||||
&CD3DX12_TEXTURE_COPY_LOCATION(std::get<1>(m_rtts.m_bound_depth_stencil), 1), nullptr);
|
||||
get_current_resource_storage().command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(std::get<1>(m_rtts.m_bound_depth_stencil), D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_DEPTH_WRITE));
|
||||
|
||||
CHECK_HRESULT(get_current_resource_storage().command_list->Close());
|
||||
m_command_queue->ExecuteCommandLists(1, (ID3D12CommandList**)get_current_resource_storage().command_list.GetAddressOf());
|
||||
get_current_resource_storage().set_new_command_list();
|
||||
|
||||
wait_for_command_queue(m_device.Get(), m_command_queue.Get());
|
||||
m_readback_resources.m_get_pos = m_readback_resources.get_current_put_pos_minus_one();
|
||||
|
||||
void *mapped_buffer = m_readback_resources.map<void>(heap_offset);
|
||||
for (unsigned row = 0; row < clip_h; row++)
|
||||
{
|
||||
char *casted_dest = (char*)buffer + row * clip_w;
|
||||
char *casted_src = (char*)mapped_buffer + row * row_pitch;
|
||||
for (unsigned col = 0; col < row_pitch; col++)
|
||||
*casted_dest++ = *casted_src++;
|
||||
}
|
||||
m_readback_resources.unmap();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -5,185 +5,26 @@
|
||||
#include "d3dx12.h"
|
||||
|
||||
#include "D3D12Formats.h"
|
||||
#include <gsl.h>
|
||||
#include "D3D12MemoryHelpers.h"
|
||||
#include "../Common/surface_store.h"
|
||||
|
||||
namespace rsx
|
||||
{
|
||||
namespace
|
||||
{
|
||||
std::vector<u8> get_rtt_indexes(u8 color_target)
|
||||
{
|
||||
switch (color_target)
|
||||
{
|
||||
case CELL_GCM_SURFACE_TARGET_NONE: return{};
|
||||
case CELL_GCM_SURFACE_TARGET_0: return{ 0 };
|
||||
case CELL_GCM_SURFACE_TARGET_1: return{ 1 };
|
||||
case CELL_GCM_SURFACE_TARGET_MRT1: return{ 0, 1 };
|
||||
case CELL_GCM_SURFACE_TARGET_MRT2: return{ 0, 1, 2 };
|
||||
case CELL_GCM_SURFACE_TARGET_MRT3: return{ 0, 1, 2, 3 };
|
||||
}
|
||||
throw EXCEPTION("Wrong color_target (%d)", color_target);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Traits>
|
||||
struct surface_store
|
||||
{
|
||||
private:
|
||||
using surface_storage_type = typename Traits::surface_storage_type;
|
||||
using surface_type = typename Traits::surface_type;
|
||||
using command_list_type = typename Traits::command_list_type;
|
||||
|
||||
std::unordered_map<u32, surface_storage_type> m_render_targets_storage = {};
|
||||
std::unordered_map<u32, surface_storage_type> m_depth_stencil_storage = {};
|
||||
|
||||
public:
|
||||
std::array<std::tuple<u32, surface_type>, 4> m_bound_render_targets = {};
|
||||
std::tuple<u32, surface_type> m_bound_depth_stencil = {};
|
||||
|
||||
std::list<surface_storage_type> invalidated_resources;
|
||||
|
||||
surface_store() = default;
|
||||
~surface_store() = default;
|
||||
surface_store(const surface_store&) = delete;
|
||||
private:
|
||||
/**
|
||||
* If render target already exists at address, issue state change operation on cmdList.
|
||||
* Otherwise create one with width, height, clearColor info.
|
||||
* returns the corresponding render target resource.
|
||||
*/
|
||||
template <typename ...Args>
|
||||
gsl::not_null<surface_type> bind_address_as_render_targets(
|
||||
command_list_type command_list,
|
||||
u32 address,
|
||||
u8 surface_color_format, size_t width, size_t height,
|
||||
Args&&... extra_params)
|
||||
{
|
||||
auto It = m_render_targets_storage.find(address);
|
||||
// TODO: Fix corner cases
|
||||
// This doesn't take overlapping surface(s) into account.
|
||||
// Invalidated surface(s) should also copy their content to the new resources.
|
||||
if (It != m_render_targets_storage.end())
|
||||
{
|
||||
surface_storage_type &rtt = It->second;
|
||||
if (Traits::rtt_has_format_width_height(rtt, surface_color_format, width, height))
|
||||
{
|
||||
Traits::prepare_rtt_for_drawing(command_list, rtt.Get());
|
||||
return rtt.Get();
|
||||
}
|
||||
invalidated_resources.push_back(std::move(rtt));
|
||||
m_render_targets_storage.erase(address);
|
||||
}
|
||||
|
||||
m_render_targets_storage[address] = Traits::create_new_render_target(address, surface_color_format, width, height, std::forward<Args>(extra_params)...);
|
||||
return m_render_targets_storage[address].Get();
|
||||
}
|
||||
|
||||
template <typename ...Args>
|
||||
gsl::not_null<surface_type> bind_address_as_depth_stencil(
|
||||
command_list_type command_list,
|
||||
u32 address,
|
||||
u8 surface_depth_format, size_t width, size_t height,
|
||||
Args&&... extra_params)
|
||||
{
|
||||
auto It = m_depth_stencil_storage.find(address);
|
||||
if (It != m_depth_stencil_storage.end())
|
||||
{
|
||||
surface_storage_type &ds = It->second;
|
||||
if (Traits::ds_has_format_width_height(ds, surface_depth_format, width, height))
|
||||
{
|
||||
Traits::prepare_ds_for_drawing(command_list, ds.Get());
|
||||
return ds.Get();
|
||||
}
|
||||
invalidated_resources.push_back(std::move(ds));
|
||||
m_depth_stencil_storage.erase(address);
|
||||
}
|
||||
|
||||
m_depth_stencil_storage[address] = Traits::create_new_depth_stencil(address, surface_depth_format, width, height, std::forward<Args>(extra_params)...);
|
||||
return m_depth_stencil_storage[address].Get();
|
||||
}
|
||||
public:
|
||||
template <typename ...Args>
|
||||
void prepare_render_target(
|
||||
command_list_type command_list,
|
||||
u32 set_surface_format_reg,
|
||||
u32 clip_horizontal_reg, u32 clip_vertical_reg,
|
||||
u32 set_surface_target,
|
||||
const std::array<u32, 4> &surface_addresses, u32 address_z,
|
||||
Args&&... extra_params)
|
||||
{
|
||||
u32 clip_width = clip_horizontal_reg >> 16;
|
||||
u32 clip_height = clip_vertical_reg >> 16;
|
||||
u32 clip_x = clip_horizontal_reg;
|
||||
u32 clip_y = clip_vertical_reg;
|
||||
|
||||
rsx::surface_info surface = {};
|
||||
surface.unpack(set_surface_format_reg);
|
||||
|
||||
// Make previous RTTs sampleable
|
||||
for (std::tuple<u32, surface_type> &rtt : m_bound_render_targets)
|
||||
{
|
||||
if (std::get<1>(rtt) != nullptr)
|
||||
Traits::prepare_rtt_for_sampling(command_list, std::get<1>(rtt));
|
||||
rtt = std::make_tuple(0, nullptr);
|
||||
}
|
||||
|
||||
// Create/Reuse requested rtts
|
||||
for (u8 surface_index : get_rtt_indexes(set_surface_target))
|
||||
{
|
||||
if (surface_addresses[surface_index] == 0)
|
||||
continue;
|
||||
|
||||
m_bound_render_targets[surface_index] = std::make_tuple(surface_addresses[surface_index],
|
||||
bind_address_as_render_targets(command_list, surface_addresses[surface_index], surface.color_format, clip_width, clip_height, std::forward<Args>(extra_params)...));
|
||||
}
|
||||
|
||||
// Same for depth buffer
|
||||
if (std::get<1>(m_bound_depth_stencil) != nullptr)
|
||||
Traits::prepare_ds_for_sampling(command_list, std::get<1>(m_bound_depth_stencil));
|
||||
m_bound_depth_stencil = std::make_tuple(0, nullptr);
|
||||
if (!address_z)
|
||||
return;
|
||||
m_bound_depth_stencil = std::make_tuple(address_z,
|
||||
bind_address_as_depth_stencil(command_list, address_z, surface.depth_format, clip_width, clip_height, std::forward<Args>(extra_params)...));
|
||||
}
|
||||
|
||||
surface_type get_texture_from_render_target_if_applicable(u32 address)
|
||||
{
|
||||
// TODO: Handle texture that overlaps one (or several) surface.
|
||||
// Handle texture conversion
|
||||
// FIXME: Disgaea 3 loading screen seems to use a subset of a surface. It's not properly handled here.
|
||||
// Note: not const because conversions/resolve/... can happen
|
||||
auto It = m_render_targets_storage.find(address);
|
||||
if (It != m_render_targets_storage.end())
|
||||
return It->second.Get();
|
||||
return surface_type();
|
||||
}
|
||||
|
||||
surface_type get_texture_from_depth_stencil_if_applicable(u32 address)
|
||||
{
|
||||
// TODO: Same as above although there wasn't any game using corner case for DS yet.
|
||||
auto It = m_depth_stencil_storage.find(address);
|
||||
if (It != m_depth_stencil_storage.end())
|
||||
return It->second.Get();
|
||||
return surface_type();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
struct render_target_traits
|
||||
{
|
||||
using surface_storage_type = ComPtr<ID3D12Resource>;
|
||||
using surface_type = ID3D12Resource*;
|
||||
using command_list_type = gsl::not_null<ID3D12GraphicsCommandList*>;
|
||||
using download_buffer_object = std::tuple<size_t, size_t, size_t, ComPtr<ID3D12Fence>, HANDLE>; // heap offset, size, last_put_pos, fence, handle
|
||||
|
||||
static
|
||||
ComPtr<ID3D12Resource> create_new_render_target(
|
||||
ComPtr<ID3D12Resource> create_new_surface(
|
||||
u32 address,
|
||||
u8 surface_color_format, size_t width, size_t height,
|
||||
surface_color_format color_format, size_t width, size_t height,
|
||||
gsl::not_null<ID3D12Device*> device, const std::array<float, 4> &clear_color, float, u8)
|
||||
{
|
||||
DXGI_FORMAT dxgi_format = get_color_surface_format(surface_color_format);
|
||||
DXGI_FORMAT dxgi_format = get_color_surface_format(color_format);
|
||||
ComPtr<ID3D12Resource> rtt;
|
||||
LOG_WARNING(RSX, "Creating RTT");
|
||||
|
||||
@@ -226,9 +67,9 @@ struct render_target_traits
|
||||
}
|
||||
|
||||
static
|
||||
ComPtr<ID3D12Resource> create_new_depth_stencil(
|
||||
ComPtr<ID3D12Resource> create_new_surface(
|
||||
u32 address,
|
||||
u8 surfaceDepthFormat, size_t width, size_t height,
|
||||
surface_depth_format surfaceDepthFormat, size_t width, size_t height,
|
||||
gsl::not_null<ID3D12Device*> device, const std::array<float, 4>& , float clear_depth, u8 clear_stencil)
|
||||
{
|
||||
D3D12_CLEAR_VALUE clear_depth_value = {};
|
||||
@@ -272,18 +113,145 @@ struct render_target_traits
|
||||
|
||||
|
||||
static
|
||||
bool rtt_has_format_width_height(const ComPtr<ID3D12Resource> &rtt, u8 surface_color_format, size_t width, size_t height)
|
||||
bool rtt_has_format_width_height(const ComPtr<ID3D12Resource> &rtt, surface_color_format surface_color_format, size_t width, size_t height)
|
||||
{
|
||||
DXGI_FORMAT dxgi_format = get_color_surface_format(surface_color_format);
|
||||
return rtt->GetDesc().Format == dxgi_format && rtt->GetDesc().Width == width && rtt->GetDesc().Height == height;
|
||||
}
|
||||
|
||||
static
|
||||
bool ds_has_format_width_height(const ComPtr<ID3D12Resource> &rtt, u8 surface_depth_stencil_format, size_t width, size_t height)
|
||||
bool ds_has_format_width_height(const ComPtr<ID3D12Resource> &rtt, surface_depth_format surface_depth_stencil_format, size_t width, size_t height)
|
||||
{
|
||||
//TODO: Check format
|
||||
return rtt->GetDesc().Width == width && rtt->GetDesc().Height == height;
|
||||
}
|
||||
|
||||
static
|
||||
std::tuple<size_t, size_t, size_t, ComPtr<ID3D12Fence>, HANDLE> issue_download_command(
|
||||
gsl::not_null<ID3D12Resource*> rtt,
|
||||
surface_color_format color_format, size_t width, size_t height,
|
||||
gsl::not_null<ID3D12Device*> device, gsl::not_null<ID3D12CommandQueue*> command_queue, data_heap &readback_heap, resource_storage &res_store
|
||||
)
|
||||
{
|
||||
ID3D12GraphicsCommandList* command_list = res_store.command_list.Get();
|
||||
DXGI_FORMAT dxgi_format = get_color_surface_format(color_format);
|
||||
size_t row_pitch = rsx::utility::get_aligned_pitch(color_format, gsl::narrow<u32>(width));
|
||||
|
||||
size_t buffer_size = row_pitch * height;
|
||||
size_t heap_offset = readback_heap.alloc<D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT>(buffer_size);
|
||||
|
||||
command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(rtt, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE));
|
||||
|
||||
command_list->CopyTextureRegion(&CD3DX12_TEXTURE_COPY_LOCATION(readback_heap.get_heap(), { heap_offset,{ dxgi_format, (UINT)width, (UINT)height, 1, (UINT)row_pitch } }), 0, 0, 0,
|
||||
&CD3DX12_TEXTURE_COPY_LOCATION(rtt, 0), nullptr);
|
||||
command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(rtt, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET));
|
||||
|
||||
CHECK_HRESULT(command_list->Close());
|
||||
command_queue->ExecuteCommandLists(1, (ID3D12CommandList**)res_store.command_list.GetAddressOf());
|
||||
res_store.set_new_command_list();
|
||||
|
||||
ComPtr<ID3D12Fence> fence;
|
||||
CHECK_HRESULT(device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(fence.GetAddressOf())));
|
||||
HANDLE handle = CreateEventEx(nullptr, FALSE, FALSE, EVENT_ALL_ACCESS);
|
||||
fence->SetEventOnCompletion(1, handle);
|
||||
command_queue->Signal(fence.Get(), 1);
|
||||
|
||||
return std::make_tuple(heap_offset, buffer_size, readback_heap.get_current_put_pos_minus_one(), fence, handle);
|
||||
}
|
||||
|
||||
static
|
||||
std::tuple<size_t, size_t, size_t, ComPtr<ID3D12Fence>, HANDLE> issue_depth_download_command(
|
||||
gsl::not_null<ID3D12Resource*> ds,
|
||||
surface_depth_format depth_format, size_t width, size_t height,
|
||||
gsl::not_null<ID3D12Device*> device, gsl::not_null<ID3D12CommandQueue*> command_queue, data_heap &readback_heap, resource_storage &res_store
|
||||
)
|
||||
{
|
||||
ID3D12GraphicsCommandList* command_list = res_store.command_list.Get();
|
||||
DXGI_FORMAT dxgi_format = (depth_format == surface_depth_format::z24s8) ? DXGI_FORMAT_R32_TYPELESS : DXGI_FORMAT_R16_TYPELESS;
|
||||
|
||||
size_t row_pitch = align(width * 4, 256);
|
||||
size_t buffer_size = row_pitch * height;
|
||||
size_t heap_offset = readback_heap.alloc<D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT>(buffer_size);
|
||||
|
||||
command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(ds, D3D12_RESOURCE_STATE_DEPTH_WRITE, D3D12_RESOURCE_STATE_COPY_SOURCE));
|
||||
|
||||
command_list->CopyTextureRegion(&CD3DX12_TEXTURE_COPY_LOCATION(readback_heap.get_heap(), { heap_offset,{ dxgi_format, (UINT)width, (UINT)height, 1, (UINT)row_pitch } }), 0, 0, 0,
|
||||
&CD3DX12_TEXTURE_COPY_LOCATION(ds, 0), nullptr);
|
||||
command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(ds, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_DEPTH_WRITE));
|
||||
|
||||
CHECK_HRESULT(command_list->Close());
|
||||
command_queue->ExecuteCommandLists(1, (ID3D12CommandList**)res_store.command_list.GetAddressOf());
|
||||
res_store.set_new_command_list();
|
||||
|
||||
ComPtr<ID3D12Fence> fence;
|
||||
CHECK_HRESULT(device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(fence.GetAddressOf())));
|
||||
HANDLE handle = CreateEventEx(nullptr, FALSE, FALSE, EVENT_ALL_ACCESS);
|
||||
fence->SetEventOnCompletion(1, handle);
|
||||
command_queue->Signal(fence.Get(), 1);
|
||||
|
||||
return std::make_tuple(heap_offset, buffer_size, readback_heap.get_current_put_pos_minus_one(), fence, handle);
|
||||
}
|
||||
|
||||
static
|
||||
std::tuple<size_t, size_t, size_t, ComPtr<ID3D12Fence>, HANDLE> issue_stencil_download_command(
|
||||
gsl::not_null<ID3D12Resource*> stencil,
|
||||
size_t width, size_t height,
|
||||
gsl::not_null<ID3D12Device*> device, gsl::not_null<ID3D12CommandQueue*> command_queue, data_heap &readback_heap, resource_storage &res_store
|
||||
)
|
||||
{
|
||||
ID3D12GraphicsCommandList* command_list = res_store.command_list.Get();
|
||||
|
||||
size_t row_pitch = align(width, 256);
|
||||
size_t buffer_size = row_pitch * height;
|
||||
size_t heap_offset = readback_heap.alloc<D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT>(buffer_size);
|
||||
|
||||
command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(stencil, D3D12_RESOURCE_STATE_DEPTH_WRITE, D3D12_RESOURCE_STATE_COPY_SOURCE));
|
||||
|
||||
command_list->CopyTextureRegion(&CD3DX12_TEXTURE_COPY_LOCATION(readback_heap.get_heap(), { heap_offset,{ DXGI_FORMAT_R8_TYPELESS, (UINT)width, (UINT)height, 1, (UINT)row_pitch } }), 0, 0, 0,
|
||||
&CD3DX12_TEXTURE_COPY_LOCATION(stencil, 1), nullptr);
|
||||
command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(stencil, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_DEPTH_WRITE));
|
||||
|
||||
CHECK_HRESULT(command_list->Close());
|
||||
command_queue->ExecuteCommandLists(1, (ID3D12CommandList**)res_store.command_list.GetAddressOf());
|
||||
res_store.set_new_command_list();
|
||||
|
||||
ComPtr<ID3D12Fence> fence;
|
||||
CHECK_HRESULT(device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(fence.GetAddressOf())));
|
||||
HANDLE handle = CreateEventEx(nullptr, FALSE, FALSE, EVENT_ALL_ACCESS);
|
||||
fence->SetEventOnCompletion(1, handle);
|
||||
command_queue->Signal(fence.Get(), 1);
|
||||
|
||||
return std::make_tuple(heap_offset, buffer_size, readback_heap.get_current_put_pos_minus_one(), fence, handle);
|
||||
}
|
||||
|
||||
static
|
||||
gsl::span<const gsl::byte> map_downloaded_buffer(const std::tuple<size_t, size_t, size_t, ComPtr<ID3D12Fence>, HANDLE> &sync_data,
|
||||
gsl::not_null<ID3D12Device*> device, gsl::not_null<ID3D12CommandQueue*> command_queue, data_heap &readback_heap, resource_storage &res_store)
|
||||
{
|
||||
size_t offset;
|
||||
size_t buffer_size;
|
||||
size_t current_put_pos_minus_one;
|
||||
HANDLE handle;
|
||||
std::tie(offset, buffer_size, current_put_pos_minus_one, std::ignore, handle) = sync_data;
|
||||
WaitForSingleObjectEx(handle, INFINITE, FALSE);
|
||||
CloseHandle(handle);
|
||||
|
||||
readback_heap.m_get_pos = current_put_pos_minus_one;
|
||||
const gsl::byte *mapped_buffer = readback_heap.map<const gsl::byte>(CD3DX12_RANGE(offset, offset + buffer_size));
|
||||
return { mapped_buffer , gsl::narrow<int>(buffer_size) };
|
||||
}
|
||||
|
||||
static
|
||||
void unmap_downloaded_buffer(const std::tuple<size_t, size_t, size_t, ComPtr<ID3D12Fence>, HANDLE> &sync_data,
|
||||
gsl::not_null<ID3D12Device*> device, gsl::not_null<ID3D12CommandQueue*> command_queue, data_heap &readback_heap, resource_storage &res_store)
|
||||
{
|
||||
readback_heap.unmap();
|
||||
}
|
||||
|
||||
static ID3D12Resource* get(const ComPtr<ID3D12Resource> &in)
|
||||
{
|
||||
return in.Get();
|
||||
}
|
||||
};
|
||||
|
||||
struct render_targets : public rsx::surface_store<render_target_traits>
|
||||
@@ -296,3 +264,4 @@ struct render_targets : public rsx::surface_store<render_target_traits>
|
||||
void init(ID3D12Device *device);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -40,6 +40,31 @@ D3D12_SAMPLER_DESC get_sampler_desc(const rsx::texture &texture)
|
||||
return samplerDesc;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
CD3DX12_RESOURCE_DESC get_texture_description(const rsx::texture &texture)
|
||||
{
|
||||
const u8 format = texture.format() & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN);
|
||||
DXGI_FORMAT dxgi_format = get_texture_format(format);
|
||||
|
||||
if (texture.dimension() == 1) // 1D texture or cubemap
|
||||
{
|
||||
return CD3DX12_RESOURCE_DESC::Tex1D(dxgi_format, texture.width(), 1, texture.mipmap());
|
||||
}
|
||||
else if (texture.dimension() == 2) // 2D texture or cubemap
|
||||
{
|
||||
// if (texture.depth() < 2);
|
||||
size_t depth = (texture.cubemap()) ? 6 : 1;
|
||||
return CD3DX12_RESOURCE_DESC::Tex2D(dxgi_format, texture.width(), texture.height(), (UINT)depth, texture.mipmap());
|
||||
}
|
||||
else if (texture.dimension() == 3) // 3d texture
|
||||
{
|
||||
return CD3DX12_RESOURCE_DESC::Tex3D(dxgi_format, texture.width(), texture.height(), texture.depth(), texture.mipmap());
|
||||
}
|
||||
throw EXCEPTION("Unknow texture dimension");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a texture residing in default heap and generate uploads commands in commandList,
|
||||
@@ -51,14 +76,6 @@ ComPtr<ID3D12Resource> upload_single_texture(
|
||||
ID3D12GraphicsCommandList *command_list,
|
||||
data_heap &texture_buffer_heap)
|
||||
{
|
||||
size_t w = texture.width(), h = texture.height();
|
||||
size_t depth = texture.depth();
|
||||
if (depth == 0) depth = 1;
|
||||
if (texture.cubemap()) depth *= 6;
|
||||
|
||||
const u8 format = texture.format() & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN);
|
||||
DXGI_FORMAT dxgi_format = get_texture_format(format);
|
||||
|
||||
size_t buffer_size = get_placed_texture_storage_size(texture, 256);
|
||||
size_t heap_offset = texture_buffer_heap.alloc<D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT>(buffer_size);
|
||||
|
||||
@@ -70,17 +87,19 @@ ComPtr<ID3D12Resource> upload_single_texture(
|
||||
CHECK_HRESULT(device->CreateCommittedResource(
|
||||
&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT),
|
||||
D3D12_HEAP_FLAG_NONE,
|
||||
&CD3DX12_RESOURCE_DESC::Tex2D(dxgi_format, (UINT)w, (UINT)h, (UINT)depth, texture.mipmap()),
|
||||
&get_texture_description(texture),
|
||||
D3D12_RESOURCE_STATE_COPY_DEST,
|
||||
nullptr,
|
||||
IID_PPV_ARGS(result.GetAddressOf())
|
||||
));
|
||||
|
||||
const u8 format = texture.format() & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN);
|
||||
DXGI_FORMAT dxgi_format = get_texture_format(format);
|
||||
size_t mip_level = 0;
|
||||
for (const MipmapLevelInfo mli : mipInfos)
|
||||
{
|
||||
command_list->CopyTextureRegion(&CD3DX12_TEXTURE_COPY_LOCATION(result.Get(), (UINT)mip_level), 0, 0, 0,
|
||||
&CD3DX12_TEXTURE_COPY_LOCATION(texture_buffer_heap.get_heap(), { heap_offset + mli.offset, { dxgi_format, (UINT)mli.width, (UINT)mli.height, 1, (UINT)mli.rowPitch } }), nullptr);
|
||||
&CD3DX12_TEXTURE_COPY_LOCATION(texture_buffer_heap.get_heap(), { heap_offset + mli.offset, { dxgi_format, (UINT)mli.width, (UINT)mli.height, (UINT)mli.depth, (UINT)mli.rowPitch } }), nullptr);
|
||||
mip_level++;
|
||||
}
|
||||
|
||||
@@ -114,20 +133,52 @@ void update_existing_texture(
|
||||
for (const MipmapLevelInfo mli : mipInfos)
|
||||
{
|
||||
command_list->CopyTextureRegion(&CD3DX12_TEXTURE_COPY_LOCATION(existing_texture, (UINT)miplevel), 0, 0, 0,
|
||||
&CD3DX12_TEXTURE_COPY_LOCATION(texture_buffer_heap.get_heap(), { heap_offset + mli.offset,{ dxgi_format, (UINT)mli.width, (UINT)mli.height, 1, (UINT)mli.rowPitch } }), nullptr);
|
||||
&CD3DX12_TEXTURE_COPY_LOCATION(texture_buffer_heap.get_heap(), { heap_offset + mli.offset,{ dxgi_format, (UINT)mli.width, (UINT)mli.height, (UINT)mli.depth, (UINT)mli.rowPitch } }), nullptr);
|
||||
miplevel++;
|
||||
}
|
||||
|
||||
command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(existing_texture, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_GENERIC_READ));
|
||||
}
|
||||
|
||||
D3D12_SHADER_RESOURCE_VIEW_DESC get_srv_descriptor_with_dimensions(const rsx::texture &tex)
|
||||
{
|
||||
D3D12_SHADER_RESOURCE_VIEW_DESC shared_resource_view_desc = {};
|
||||
if (tex.dimension() == 1)
|
||||
{
|
||||
shared_resource_view_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1D;
|
||||
shared_resource_view_desc.Texture1D.MipLevels = tex.mipmap();
|
||||
return shared_resource_view_desc;
|
||||
}
|
||||
if (tex.dimension() == 2)
|
||||
{
|
||||
if (tex.cubemap())
|
||||
{
|
||||
shared_resource_view_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBE;
|
||||
shared_resource_view_desc.TextureCube.MipLevels = tex.mipmap();
|
||||
return shared_resource_view_desc;
|
||||
}
|
||||
shared_resource_view_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
|
||||
shared_resource_view_desc.Texture2D.MipLevels = tex.mipmap();
|
||||
return shared_resource_view_desc;
|
||||
}
|
||||
if (tex.dimension() == 3)
|
||||
{
|
||||
shared_resource_view_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE3D;
|
||||
shared_resource_view_desc.Texture3D.MipLevels = tex.mipmap();
|
||||
return shared_resource_view_desc;
|
||||
}
|
||||
throw EXCEPTION("Wrong texture dimension %d", tex.dimension());
|
||||
}
|
||||
}
|
||||
|
||||
void D3D12GSRender::upload_and_bind_textures(ID3D12GraphicsCommandList *command_list, size_t descriptor_index, size_t texture_count)
|
||||
void D3D12GSRender::upload_and_bind_textures(ID3D12GraphicsCommandList *command_list, size_t texture_count)
|
||||
{
|
||||
size_t used_texture = 0;
|
||||
|
||||
for (u32 i = 0; i < rsx::limits::textures_count; ++i)
|
||||
for (u32 i = 0; i < 16; ++i)
|
||||
{
|
||||
if (!m_textures_dirty[i])
|
||||
continue;
|
||||
m_textures_dirty[i] = false;
|
||||
|
||||
if (!textures[i].enabled())
|
||||
{
|
||||
// Now fill remaining texture slots with dummy texture/sampler
|
||||
@@ -141,21 +192,14 @@ void D3D12GSRender::upload_and_bind_textures(ID3D12GraphicsCommandList *command_
|
||||
D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_0,
|
||||
D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_0,
|
||||
D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_0);
|
||||
m_device->CreateShaderResourceView(m_dummy_texture, &shader_resource_view_desc,
|
||||
CD3DX12_CPU_DESCRIPTOR_HANDLE(get_current_resource_storage().descriptors_heap->GetCPUDescriptorHandleForHeapStart())
|
||||
.Offset((INT)descriptor_index + (INT)used_texture, g_descriptor_stride_srv_cbv_uav)
|
||||
);
|
||||
m_current_shader_resources[i] = std::make_tuple(m_dummy_texture, shader_resource_view_desc);
|
||||
|
||||
D3D12_SAMPLER_DESC sampler_desc = {};
|
||||
sampler_desc.Filter = D3D12_FILTER_MIN_MAG_MIP_POINT;
|
||||
sampler_desc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
|
||||
sampler_desc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
|
||||
sampler_desc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
|
||||
m_device->CreateSampler(&sampler_desc,
|
||||
CD3DX12_CPU_DESCRIPTOR_HANDLE(get_current_resource_storage().sampler_descriptor_heap[get_current_resource_storage().sampler_descriptors_heap_index]->GetCPUDescriptorHandleForHeapStart())
|
||||
.Offset((INT)get_current_resource_storage().current_sampler_index + (INT)used_texture, g_descriptor_stride_samplers)
|
||||
);
|
||||
used_texture++;
|
||||
m_current_samplers[i] = sampler_desc;
|
||||
continue;
|
||||
}
|
||||
size_t w = textures[i].width(), h = textures[i].height();
|
||||
@@ -178,7 +222,7 @@ void D3D12GSRender::upload_and_bind_textures(ID3D12GraphicsCommandList *command_
|
||||
{
|
||||
is_depth_stencil_texture = true;
|
||||
}
|
||||
else if (cached_texture != nullptr && (cached_texture->first == texture_entry(format, w, h, textures[i].mipmap())))
|
||||
else if (cached_texture != nullptr && (cached_texture->first == texture_entry(format, w, h, textures[i].depth(), textures[i].mipmap())))
|
||||
{
|
||||
if (cached_texture->first.m_is_dirty)
|
||||
{
|
||||
@@ -195,20 +239,10 @@ void D3D12GSRender::upload_and_bind_textures(ID3D12GraphicsCommandList *command_
|
||||
std::wstring name = L"texture_@" + std::to_wstring(texaddr);
|
||||
tex->SetName(name.c_str());
|
||||
vram_texture = tex.Get();
|
||||
m_texture_cache.store_and_protect_data(texaddr, texaddr, get_texture_size(textures[i]), format, w, h, textures[i].mipmap(), tex);
|
||||
m_texture_cache.store_and_protect_data(texaddr, texaddr, get_texture_size(textures[i]), format, w, h, textures[i].depth(), textures[i].mipmap(), tex);
|
||||
}
|
||||
|
||||
D3D12_SHADER_RESOURCE_VIEW_DESC shared_resource_view_desc = {};
|
||||
if (textures[i].cubemap())
|
||||
{
|
||||
shared_resource_view_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBE;
|
||||
shared_resource_view_desc.TextureCube.MipLevels = textures[i].mipmap();
|
||||
}
|
||||
else
|
||||
{
|
||||
shared_resource_view_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
|
||||
shared_resource_view_desc.Texture2D.MipLevels = textures[i].mipmap();
|
||||
}
|
||||
D3D12_SHADER_RESOURCE_VIEW_DESC shared_resource_view_desc = get_srv_descriptor_with_dimensions(textures[i]);
|
||||
shared_resource_view_desc.Format = get_texture_format(format);
|
||||
|
||||
switch (format)
|
||||
@@ -318,9 +352,7 @@ void D3D12GSRender::upload_and_bind_textures(ID3D12GraphicsCommandList *command_
|
||||
break;
|
||||
}
|
||||
|
||||
m_device->CreateShaderResourceView(vram_texture, &shared_resource_view_desc,
|
||||
CD3DX12_CPU_DESCRIPTOR_HANDLE(get_current_resource_storage().descriptors_heap->GetCPUDescriptorHandleForHeapStart())
|
||||
.Offset((UINT)descriptor_index + (UINT)used_texture, g_descriptor_stride_srv_cbv_uav));
|
||||
m_current_shader_resources[i] = std::make_tuple(vram_texture, shared_resource_view_desc);
|
||||
|
||||
if (get_current_resource_storage().current_sampler_index + 16 > 2048)
|
||||
{
|
||||
@@ -334,13 +366,7 @@ void D3D12GSRender::upload_and_bind_textures(ID3D12GraphicsCommandList *command_
|
||||
};
|
||||
command_list->SetDescriptorHeaps(2, descriptors);
|
||||
}
|
||||
m_device->CreateSampler(&get_sampler_desc(textures[i]),
|
||||
CD3DX12_CPU_DESCRIPTOR_HANDLE(get_current_resource_storage().sampler_descriptor_heap[get_current_resource_storage().sampler_descriptors_heap_index]->GetCPUDescriptorHandleForHeapStart())
|
||||
.Offset((UINT)get_current_resource_storage().current_sampler_index + (UINT)used_texture, g_descriptor_stride_samplers));
|
||||
|
||||
used_texture++;
|
||||
m_current_samplers[i] = get_sampler_desc(textures[i]);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -47,7 +47,7 @@ std::pair<ID3DBlob *, ID3DBlob *> compileF32toU8CS()
|
||||
}
|
||||
|
||||
|
||||
void D3D12GSRender::Shader::Init(ID3D12Device *device, ID3D12CommandQueue *gfxcommandqueue)
|
||||
void D3D12GSRender::shader::init(ID3D12Device *device, ID3D12CommandQueue *gfx_command_queue)
|
||||
{
|
||||
const char *fsCode = STRINGIFY(
|
||||
Texture2D InputTexture : register(t0); \n
|
||||
@@ -143,21 +143,21 @@ void D3D12GSRender::Shader::Init(ID3D12Device *device, ID3D12CommandQueue *gfxco
|
||||
Microsoft::WRL::ComPtr<ID3DBlob> rootSignatureBlob;
|
||||
|
||||
CHECK_HRESULT(wrapD3D12SerializeRootSignature(&rootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &rootSignatureBlob, &errorBlob));
|
||||
CHECK_HRESULT(device->CreateRootSignature(0, rootSignatureBlob->GetBufferPointer(), rootSignatureBlob->GetBufferSize(), IID_PPV_ARGS(&m_rootSignature)));
|
||||
CHECK_HRESULT(device->CreateRootSignature(0, rootSignatureBlob->GetBufferPointer(), rootSignatureBlob->GetBufferSize(), IID_PPV_ARGS(&root_signature)));
|
||||
|
||||
psoDesc.pRootSignature = m_rootSignature;
|
||||
psoDesc.pRootSignature = root_signature;
|
||||
psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
|
||||
psoDesc.BlendState.RenderTarget[0].RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
|
||||
|
||||
CHECK_HRESULT(device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&m_PSO)));
|
||||
CHECK_HRESULT(device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&pso)));
|
||||
|
||||
D3D12_DESCRIPTOR_HEAP_DESC textureHeapDesc = { D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV , 2, D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE };
|
||||
CHECK_HRESULT(
|
||||
device->CreateDescriptorHeap(&textureHeapDesc, IID_PPV_ARGS(&m_textureDescriptorHeap))
|
||||
device->CreateDescriptorHeap(&textureHeapDesc, IID_PPV_ARGS(&texture_descriptor_heap))
|
||||
);
|
||||
D3D12_DESCRIPTOR_HEAP_DESC samplerHeapDesc = { D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER , 2, D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE };
|
||||
CHECK_HRESULT(
|
||||
device->CreateDescriptorHeap(&samplerHeapDesc, IID_PPV_ARGS(&m_samplerDescriptorHeap))
|
||||
device->CreateDescriptorHeap(&samplerHeapDesc, IID_PPV_ARGS(&sampler_descriptor_heap))
|
||||
);
|
||||
|
||||
ComPtr<ID3D12Fence> fence;
|
||||
@@ -197,37 +197,37 @@ void D3D12GSRender::Shader::Init(ID3D12Device *device, ID3D12CommandQueue *gfxco
|
||||
&CD3DX12_RESOURCE_DESC::Buffer(16 * sizeof(float)),
|
||||
D3D12_RESOURCE_STATE_COPY_DEST,
|
||||
nullptr,
|
||||
IID_PPV_ARGS(&m_vertexBuffer)
|
||||
IID_PPV_ARGS(&vertex_buffer)
|
||||
));
|
||||
|
||||
D3D12_SUBRESOURCE_DATA vertexData = { reinterpret_cast<BYTE*>(quadVertex), 16 * sizeof(float), 1 };
|
||||
|
||||
UpdateSubresources(cmdList.Get(), m_vertexBuffer, intermediateBuffer.Get(), 0, 0, 1, &vertexData);
|
||||
cmdList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_vertexBuffer, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER));
|
||||
UpdateSubresources(cmdList.Get(), vertex_buffer, intermediateBuffer.Get(), 0, 0, 1, &vertexData);
|
||||
cmdList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(vertex_buffer, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER));
|
||||
CHECK_HRESULT(cmdList->Close());
|
||||
|
||||
gfxcommandqueue->ExecuteCommandLists(1, CommandListCast(cmdList.GetAddressOf()));
|
||||
gfx_command_queue->ExecuteCommandLists(1, CommandListCast(cmdList.GetAddressOf()));
|
||||
|
||||
// Now wait until upload has completed
|
||||
gfxcommandqueue->Signal(fence.Get(), 1);
|
||||
gfx_command_queue->Signal(fence.Get(), 1);
|
||||
WaitForSingleObjectEx(handle, INFINITE, FALSE);
|
||||
CloseHandle(handle);
|
||||
}
|
||||
|
||||
void D3D12GSRender::initConvertShader()
|
||||
void D3D12GSRender::init_convert_shader()
|
||||
{
|
||||
const auto &p = compileF32toU8CS();
|
||||
CHECK_HRESULT(
|
||||
m_device->CreateRootSignature(0, p.second->GetBufferPointer(), p.second->GetBufferSize(), IID_PPV_ARGS(&m_convertRootSignature))
|
||||
m_device->CreateRootSignature(0, p.second->GetBufferPointer(), p.second->GetBufferSize(), IID_PPV_ARGS(&m_convert_root_signature))
|
||||
);
|
||||
|
||||
D3D12_COMPUTE_PIPELINE_STATE_DESC computePipelineStateDesc = {};
|
||||
computePipelineStateDesc.CS.BytecodeLength = p.first->GetBufferSize();
|
||||
computePipelineStateDesc.CS.pShaderBytecode = p.first->GetBufferPointer();
|
||||
computePipelineStateDesc.pRootSignature = m_convertRootSignature;
|
||||
computePipelineStateDesc.pRootSignature = m_convert_root_signature;
|
||||
|
||||
CHECK_HRESULT(
|
||||
m_device->CreateComputePipelineState(&computePipelineStateDesc, IID_PPV_ARGS(&m_convertPSO))
|
||||
m_device->CreateComputePipelineState(&computePipelineStateDesc, IID_PPV_ARGS(&m_convert_pso))
|
||||
);
|
||||
|
||||
p.first->Release();
|
||||
|
||||
@@ -33,39 +33,43 @@ void D3D12VertexProgramDecompiler::insertHeader(std::stringstream &OS)
|
||||
OS << " float4x4 scaleOffsetMat;" << std::endl;
|
||||
OS << " int isAlphaTested;" << std::endl;
|
||||
OS << " float alphaRef;" << std::endl;
|
||||
OS << " int tex0_is_unorm;" << std::endl;
|
||||
OS << " int tex1_is_unorm;" << std::endl;
|
||||
OS << " int tex2_is_unorm;" << std::endl;
|
||||
OS << " int tex3_is_unorm;" << std::endl;
|
||||
OS << " int tex4_is_unorm;" << std::endl;
|
||||
OS << " int tex5_is_unorm;" << std::endl;
|
||||
OS << " int tex6_is_unorm;" << std::endl;
|
||||
OS << " int tex7_is_unorm;" << std::endl;
|
||||
OS << " int tex8_is_unorm;" << std::endl;
|
||||
OS << " int tex9_is_unorm;" << std::endl;
|
||||
OS << " int tex10_is_unorm;" << std::endl;
|
||||
OS << " int tex11_is_unorm;" << std::endl;
|
||||
OS << " int tex12_is_unorm;" << std::endl;
|
||||
OS << " int tex13_is_unorm;" << std::endl;
|
||||
OS << " int tex14_is_unorm;" << std::endl;
|
||||
OS << " int tex15_is_unorm;" << std::endl;
|
||||
OS << "};" << std::endl;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
bool declare_input(std::stringstream & OS, const std::tuple<size_t, std::string> &attribute, const std::vector<rsx_vertex_input> &inputs, size_t reg)
|
||||
{
|
||||
for (const auto &real_input : inputs)
|
||||
{
|
||||
if (static_cast<size_t>(real_input.location) != std::get<0>(attribute))
|
||||
continue;
|
||||
OS << "Buffer<float4> " << std::get<1>(attribute) << "_buffer : register(t" << reg++ << ");\n";
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void D3D12VertexProgramDecompiler::insertInputs(std::stringstream & OS, const std::vector<ParamType>& inputs)
|
||||
{
|
||||
OS << "struct VertexInput" << std::endl;
|
||||
OS << "{" << std::endl;
|
||||
std::vector<std::tuple<size_t, std::string>> input_data;
|
||||
for (const ParamType PT : inputs)
|
||||
{
|
||||
for (const ParamItem &PI : PT.items)
|
||||
{
|
||||
OS << " " << PT.type << " " << PI.name << ": TEXCOORD" << PI.location << ";" << std::endl;
|
||||
input_slots.push_back(PI.location);
|
||||
input_data.push_back(std::make_tuple(PI.location, PI.name));
|
||||
}
|
||||
}
|
||||
OS << "};" << std::endl;
|
||||
|
||||
std::sort(input_data.begin(), input_data.end());
|
||||
|
||||
size_t t_register = 0;
|
||||
for (const auto &attribute : input_data)
|
||||
{
|
||||
if (declare_input(OS, attribute, rsx_vertex_program.rsx_vertex_inputs, t_register))
|
||||
t_register++;
|
||||
}
|
||||
}
|
||||
|
||||
void D3D12VertexProgramDecompiler::insertConstants(std::stringstream & OS, const std::vector<ParamType> & constants)
|
||||
@@ -140,9 +144,41 @@ static const reg_info reg_table[] =
|
||||
{ "tc8", true, "dst_reg15", "", false },
|
||||
};
|
||||
|
||||
namespace
|
||||
{
|
||||
void add_input(std::stringstream & OS, const ParamItem &PI, const std::vector<rsx_vertex_input> &inputs)
|
||||
{
|
||||
for (const auto &real_input : inputs)
|
||||
{
|
||||
if (real_input.location != PI.location)
|
||||
continue;
|
||||
if (!real_input.is_array)
|
||||
{
|
||||
OS << " float4 " << PI.name << " = " << PI.name << "_buffer[0];\n";
|
||||
return;
|
||||
}
|
||||
if (real_input.frequency > 1)
|
||||
{
|
||||
if (real_input.is_modulo)
|
||||
{
|
||||
OS << " float4 " << PI.name << " = " << PI.name << "_buffer[vertex_id % " << real_input.frequency << "];\n";
|
||||
return;
|
||||
}
|
||||
OS << " float4 " << PI.name << " = " << PI.name << "_buffer[vertex_id / " << real_input.frequency << "];\n";
|
||||
return;
|
||||
}
|
||||
OS << " float4 " << PI.name << " = " << PI.name << "_buffer[vertex_id];\n";
|
||||
return;
|
||||
}
|
||||
OS << " float4 " << PI.name << " = float4(0., 0., 0., 1.);\n";
|
||||
}
|
||||
}
|
||||
|
||||
void D3D12VertexProgramDecompiler::insertMainStart(std::stringstream & OS)
|
||||
{
|
||||
OS << "PixelInput main(VertexInput In)" << std::endl;
|
||||
insert_d3d12_legacy_function(OS);
|
||||
|
||||
OS << "PixelInput main(uint vertex_id : SV_VertexID)" << std::endl;
|
||||
OS << "{" << std::endl;
|
||||
|
||||
// Declare inside main function
|
||||
@@ -162,7 +198,9 @@ void D3D12VertexProgramDecompiler::insertMainStart(std::stringstream & OS)
|
||||
for (const ParamType PT : m_parr.params[PF_PARAM_IN])
|
||||
{
|
||||
for (const ParamItem &PI : PT.items)
|
||||
OS << " " << PT.type << " " << PI.name << " = In." << PI.name << ";" << std::endl;
|
||||
{
|
||||
add_input(OS, PI, rsx_vertex_program.rsx_vertex_inputs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,7 +220,7 @@ void D3D12VertexProgramDecompiler::insertMainEnd(std::stringstream & OS)
|
||||
}
|
||||
|
||||
D3D12VertexProgramDecompiler::D3D12VertexProgramDecompiler(const RSXVertexProgram &prog) :
|
||||
VertexProgramDecompiler(prog)
|
||||
VertexProgramDecompiler(prog), rsx_vertex_program(prog)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -18,7 +18,8 @@ protected:
|
||||
virtual void insertOutputs(std::stringstream &OS, const std::vector<ParamType> &outputs);
|
||||
virtual void insertMainStart(std::stringstream &OS);
|
||||
virtual void insertMainEnd(std::stringstream &OS);
|
||||
|
||||
const RSXVertexProgram &rsx_vertex_program;
|
||||
public:
|
||||
std::vector<size_t> input_slots;
|
||||
D3D12VertexProgramDecompiler(const RSXVertexProgram &prog);
|
||||
};
|
||||
|
||||
+250
-71
@@ -719,49 +719,156 @@ namespace
|
||||
};
|
||||
}
|
||||
|
||||
Vertex_base_type to_vertex_base_type(u8 in)
|
||||
rsx::vertex_base_type rsx::to_vertex_base_type(u8 in)
|
||||
{
|
||||
switch (in)
|
||||
{
|
||||
case 1: return Vertex_base_type::s1;
|
||||
case 2: return Vertex_base_type::f;
|
||||
case 3: return Vertex_base_type::sf;
|
||||
case 4: return Vertex_base_type::ub;
|
||||
case 5: return Vertex_base_type::s32k;
|
||||
case 6: return Vertex_base_type::cmp;
|
||||
case 7: return Vertex_base_type::ub256;
|
||||
case 1: return rsx::vertex_base_type::s1;
|
||||
case 2: return rsx::vertex_base_type::f;
|
||||
case 3: return rsx::vertex_base_type::sf;
|
||||
case 4: return rsx::vertex_base_type::ub;
|
||||
case 5: return rsx::vertex_base_type::s32k;
|
||||
case 6: return rsx::vertex_base_type::cmp;
|
||||
case 7: return rsx::vertex_base_type::ub256;
|
||||
}
|
||||
throw new EXCEPTION("Unknow vertex base type %d", in);
|
||||
}
|
||||
|
||||
Index_array_type to_index_array_type(u8 in)
|
||||
rsx::index_array_type rsx::to_index_array_type(u8 in)
|
||||
{
|
||||
switch (in)
|
||||
{
|
||||
case 0: return Index_array_type::unsigned_32b;
|
||||
case 1: return Index_array_type::unsigned_16b;
|
||||
case 0: return rsx::index_array_type::u32;
|
||||
case 1: return rsx::index_array_type::u16;
|
||||
}
|
||||
throw new EXCEPTION("Unknown index array type %d", in);
|
||||
}
|
||||
|
||||
Primitive_type to_primitive_type(u8 in)
|
||||
rsx::primitive_type rsx::to_primitive_type(u8 in)
|
||||
{
|
||||
switch (in)
|
||||
{
|
||||
case 1: return Primitive_type::points;
|
||||
case 2: return Primitive_type::lines;
|
||||
case 3: return Primitive_type::line_loop;
|
||||
case 4: return Primitive_type::line_strip;
|
||||
case 5: return Primitive_type::triangles;
|
||||
case 6: return Primitive_type::triangle_strip;
|
||||
case 7: return Primitive_type::triangle_fan;
|
||||
case 8: return Primitive_type::quads;
|
||||
case 9: return Primitive_type::quad_strip;
|
||||
case 10: return Primitive_type::polygon;
|
||||
case 1: return rsx::primitive_type::points;
|
||||
case 2: return rsx::primitive_type::lines;
|
||||
case 3: return rsx::primitive_type::line_loop;
|
||||
case 4: return rsx::primitive_type::line_strip;
|
||||
case 5: return rsx::primitive_type::triangles;
|
||||
case 6: return rsx::primitive_type::triangle_strip;
|
||||
case 7: return rsx::primitive_type::triangle_fan;
|
||||
case 8: return rsx::primitive_type::quads;
|
||||
case 9: return rsx::primitive_type::quad_strip;
|
||||
case 10: return rsx::primitive_type::polygon;
|
||||
}
|
||||
throw new EXCEPTION("Unknow primitive type %d", in);
|
||||
}
|
||||
|
||||
enum
|
||||
{
|
||||
CELL_GCM_WINDOW_ORIGIN_TOP = 0,
|
||||
CELL_GCM_WINDOW_ORIGIN_BOTTOM = 1,
|
||||
CELL_GCM_WINDOW_PIXEL_CENTER_HALF = 0,
|
||||
CELL_GCM_WINDOW_PIXEL_CENTER_INTEGER = 1,
|
||||
};
|
||||
|
||||
rsx::window_origin rsx::to_window_origin(u8 in)
|
||||
{
|
||||
switch (in)
|
||||
{
|
||||
case CELL_GCM_WINDOW_ORIGIN_TOP: return rsx::window_origin::top;
|
||||
case CELL_GCM_WINDOW_ORIGIN_BOTTOM: return rsx::window_origin::bottom;
|
||||
}
|
||||
throw EXCEPTION("Unknow window origin modifier %x", in);
|
||||
}
|
||||
|
||||
rsx::window_pixel_center rsx::to_window_pixel_center(u8 in)
|
||||
{
|
||||
switch (in)
|
||||
{
|
||||
case CELL_GCM_WINDOW_PIXEL_CENTER_HALF: return rsx::window_pixel_center::half;
|
||||
case CELL_GCM_WINDOW_PIXEL_CENTER_INTEGER: return rsx::window_pixel_center::integer;
|
||||
}
|
||||
throw EXCEPTION("Unknow window pixel center %x", in);
|
||||
}
|
||||
|
||||
rsx::comparaison_function rsx::to_comparaison_function(u16 in)
|
||||
{
|
||||
switch (in)
|
||||
{
|
||||
case CELL_GCM_NEVER: return rsx::comparaison_function::never;
|
||||
case CELL_GCM_LESS: return rsx::comparaison_function::less;
|
||||
case CELL_GCM_EQUAL: return rsx::comparaison_function::equal;
|
||||
case CELL_GCM_LEQUAL: return rsx::comparaison_function::less_or_equal;
|
||||
case CELL_GCM_GREATER: return rsx::comparaison_function::greater;
|
||||
case CELL_GCM_NOTEQUAL: return rsx::comparaison_function::not_equal;
|
||||
case CELL_GCM_GEQUAL: return rsx::comparaison_function::greater_or_equal;
|
||||
case CELL_GCM_ALWAYS: return rsx::comparaison_function::always;
|
||||
}
|
||||
throw EXCEPTION("Wrong comparaison function %x", in);
|
||||
}
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
// Surface Target
|
||||
CELL_GCM_SURFACE_TARGET_NONE = 0,
|
||||
CELL_GCM_SURFACE_TARGET_0 = 1,
|
||||
CELL_GCM_SURFACE_TARGET_1 = 2,
|
||||
CELL_GCM_SURFACE_TARGET_MRT1 = 0x13,
|
||||
CELL_GCM_SURFACE_TARGET_MRT2 = 0x17,
|
||||
CELL_GCM_SURFACE_TARGET_MRT3 = 0x1f,
|
||||
|
||||
// Surface Depth
|
||||
CELL_GCM_SURFACE_Z16 = 1,
|
||||
CELL_GCM_SURFACE_Z24S8 = 2,
|
||||
|
||||
// Surface Antialias
|
||||
CELL_GCM_SURFACE_CENTER_1 = 0,
|
||||
CELL_GCM_SURFACE_DIAGONAL_CENTERED_2 = 3,
|
||||
CELL_GCM_SURFACE_SQUARE_CENTERED_4 = 4,
|
||||
CELL_GCM_SURFACE_SQUARE_ROTATED_4 = 5,
|
||||
|
||||
// Surface format
|
||||
CELL_GCM_SURFACE_X1R5G5B5_Z1R5G5B5 = 1,
|
||||
CELL_GCM_SURFACE_X1R5G5B5_O1R5G5B5 = 2,
|
||||
CELL_GCM_SURFACE_R5G6B5 = 3,
|
||||
CELL_GCM_SURFACE_X8R8G8B8_Z8R8G8B8 = 4,
|
||||
CELL_GCM_SURFACE_X8R8G8B8_O8R8G8B8 = 5,
|
||||
CELL_GCM_SURFACE_A8R8G8B8 = 8,
|
||||
CELL_GCM_SURFACE_B8 = 9,
|
||||
CELL_GCM_SURFACE_G8B8 = 10,
|
||||
CELL_GCM_SURFACE_F_W16Z16Y16X16 = 11,
|
||||
CELL_GCM_SURFACE_F_W32Z32Y32X32 = 12,
|
||||
CELL_GCM_SURFACE_F_X32 = 13,
|
||||
CELL_GCM_SURFACE_X8B8G8R8_Z8B8G8R8 = 14,
|
||||
CELL_GCM_SURFACE_X8B8G8R8_O8B8G8R8 = 15,
|
||||
CELL_GCM_SURFACE_A8B8G8R8 = 16,
|
||||
|
||||
};
|
||||
|
||||
rsx::surface_target rsx::to_surface_target(u8 in)
|
||||
{
|
||||
switch (in)
|
||||
{
|
||||
case CELL_GCM_SURFACE_TARGET_NONE: return rsx::surface_target::none;
|
||||
case CELL_GCM_SURFACE_TARGET_0: return rsx::surface_target::surface_a;
|
||||
case CELL_GCM_SURFACE_TARGET_1: return rsx::surface_target::surface_b;
|
||||
case CELL_GCM_SURFACE_TARGET_MRT1: return rsx::surface_target::surfaces_a_b;
|
||||
case CELL_GCM_SURFACE_TARGET_MRT2: return rsx::surface_target::surfaces_a_b_c;
|
||||
case CELL_GCM_SURFACE_TARGET_MRT3: return rsx::surface_target::surfaces_a_b_c_d;
|
||||
}
|
||||
throw EXCEPTION("Unknow surface target %x", in);
|
||||
}
|
||||
|
||||
rsx::surface_depth_format rsx::to_surface_depth_format(u8 in)
|
||||
{
|
||||
switch (in)
|
||||
{
|
||||
case CELL_GCM_SURFACE_Z16: return rsx::surface_depth_format::z16;
|
||||
case CELL_GCM_SURFACE_Z24S8: return rsx::surface_depth_format::z24s8;
|
||||
}
|
||||
throw EXCEPTION("Unknow surface depth format %x", in);
|
||||
}
|
||||
|
||||
std::string rsx::get_method_name(const u32 id)
|
||||
{
|
||||
auto found = methods.find(id);
|
||||
@@ -773,6 +880,40 @@ std::string rsx::get_method_name(const u32 id)
|
||||
return fmt::format("unknown/illegal method [0x%08x]", id);
|
||||
}
|
||||
|
||||
rsx::surface_antialiasing rsx::to_surface_antialiasing(u8 in)
|
||||
{
|
||||
switch (in)
|
||||
{
|
||||
case CELL_GCM_SURFACE_CENTER_1: return rsx::surface_antialiasing::center_1_sample;
|
||||
case CELL_GCM_SURFACE_DIAGONAL_CENTERED_2: return rsx::surface_antialiasing::diagonal_centered_2_samples;
|
||||
case CELL_GCM_SURFACE_SQUARE_CENTERED_4: return rsx::surface_antialiasing::square_centered_4_samples;
|
||||
case CELL_GCM_SURFACE_SQUARE_ROTATED_4: return rsx::surface_antialiasing::square_rotated_4_samples;
|
||||
}
|
||||
throw EXCEPTION("unknow surface antialiasing format %x", in);
|
||||
}
|
||||
|
||||
rsx::surface_color_format rsx::to_surface_color_format(u8 in)
|
||||
{
|
||||
switch (in)
|
||||
{
|
||||
case CELL_GCM_SURFACE_X1R5G5B5_Z1R5G5B5: return rsx::surface_color_format::x1r5g5b5_z1r5g5b5;
|
||||
case CELL_GCM_SURFACE_X1R5G5B5_O1R5G5B5: return rsx::surface_color_format::x1r5g5b5_o1r5g5b5;
|
||||
case CELL_GCM_SURFACE_R5G6B5: return rsx::surface_color_format::r5g6b5;
|
||||
case CELL_GCM_SURFACE_X8R8G8B8_Z8R8G8B8: return rsx::surface_color_format::x8r8g8b8_z8r8g8b8;
|
||||
case CELL_GCM_SURFACE_X8R8G8B8_O8R8G8B8: return rsx::surface_color_format::x8r8g8b8_o8r8g8b8;
|
||||
case CELL_GCM_SURFACE_A8R8G8B8: return rsx::surface_color_format::a8r8g8b8;
|
||||
case CELL_GCM_SURFACE_B8: return rsx::surface_color_format::b8;
|
||||
case CELL_GCM_SURFACE_G8B8: return rsx::surface_color_format::g8b8;
|
||||
case CELL_GCM_SURFACE_F_W16Z16Y16X16: return rsx::surface_color_format::w16z16y16x16;
|
||||
case CELL_GCM_SURFACE_F_W32Z32Y32X32: return rsx::surface_color_format::w32z32y32x32;
|
||||
case CELL_GCM_SURFACE_F_X32: return rsx::surface_color_format::x32;
|
||||
case CELL_GCM_SURFACE_X8B8G8R8_Z8B8G8R8: return rsx::surface_color_format::x8b8g8r8_z8b8g8r8;
|
||||
case CELL_GCM_SURFACE_X8B8G8R8_O8B8G8R8: return rsx::surface_color_format::x8b8g8r8_o8b8g8r8;
|
||||
case CELL_GCM_SURFACE_A8B8G8R8: return rsx::surface_color_format::a8b8g8r8;
|
||||
}
|
||||
throw EXCEPTION("unknow surface color format %x", in);
|
||||
}
|
||||
|
||||
// Various parameter pretty printing function
|
||||
namespace
|
||||
{
|
||||
@@ -856,18 +997,18 @@ namespace
|
||||
|
||||
std::string get_primitive_mode(u8 draw_mode)
|
||||
{
|
||||
switch (to_primitive_type(draw_mode))
|
||||
switch (rsx::to_primitive_type(draw_mode))
|
||||
{
|
||||
case Primitive_type::points: return "Points";
|
||||
case Primitive_type::lines: return "Lines";
|
||||
case Primitive_type::line_loop: return "Line_loop";
|
||||
case Primitive_type::line_strip: return "Line_strip";
|
||||
case Primitive_type::triangles: return "Triangles";
|
||||
case Primitive_type::triangle_strip: return "Triangle_strip";
|
||||
case Primitive_type::triangle_fan: return "Triangle_fan";
|
||||
case Primitive_type::quads: return "Quads";
|
||||
case Primitive_type::quad_strip: return "Quad_strip";
|
||||
case Primitive_type::polygon: return "Polygon";
|
||||
case rsx::primitive_type::points: return "Points";
|
||||
case rsx::primitive_type::lines: return "Lines";
|
||||
case rsx::primitive_type::line_loop: return "Line_loop";
|
||||
case rsx::primitive_type::line_strip: return "Line_strip";
|
||||
case rsx::primitive_type::triangles: return "Triangles";
|
||||
case rsx::primitive_type::triangle_strip: return "Triangle_strip";
|
||||
case rsx::primitive_type::triangle_fan: return "Triangle_fan";
|
||||
case rsx::primitive_type::quads: return "Quads";
|
||||
case rsx::primitive_type::quad_strip: return "Quad_strip";
|
||||
case rsx::primitive_type::polygon: return "Polygon";
|
||||
}
|
||||
return "Error";
|
||||
}
|
||||
@@ -892,46 +1033,58 @@ namespace
|
||||
|
||||
std::string depth_stencil_surface_format(u32 format)
|
||||
{
|
||||
switch (format)
|
||||
switch (rsx::to_surface_depth_format(format))
|
||||
{
|
||||
case CELL_GCM_SURFACE_Z16: return "CELL_GCM_SURFACE_Z16";
|
||||
case CELL_GCM_SURFACE_Z24S8: return "CELL_GCM_SURFACE_Z24S8";
|
||||
case rsx::surface_depth_format::z16: return "CELL_GCM_SURFACE_Z16";
|
||||
case rsx::surface_depth_format::z24s8: return "CELL_GCM_SURFACE_Z24S8";
|
||||
}
|
||||
return "Error";
|
||||
}
|
||||
|
||||
std::string color_surface_format(u32 format)
|
||||
std::string surface_antialiasing(u8 format)
|
||||
{
|
||||
switch (format)
|
||||
switch (rsx::to_surface_antialiasing(format))
|
||||
{
|
||||
case CELL_GCM_SURFACE_X1R5G5B5_Z1R5G5B5: return "CELL_GCM_SURFACE_X1R5G5B5_Z1R5G5B5";
|
||||
case CELL_GCM_SURFACE_X1R5G5B5_O1R5G5B5: return "CELL_GCM_SURFACE_X1R5G5B5_O1R5G5B5";
|
||||
case CELL_GCM_SURFACE_R5G6B5: return "CELL_GCM_SURFACE_R5G6B5";
|
||||
case CELL_GCM_SURFACE_X8R8G8B8_Z8R8G8B8: return "CELL_GCM_SURFACE_X8R8G8B8_Z8R8G8B8";
|
||||
case CELL_GCM_SURFACE_X8R8G8B8_O8R8G8B8: return "CELL_GCM_SURFACE_X8R8G8B8_O8R8G8B8";
|
||||
case CELL_GCM_SURFACE_A8R8G8B8: return "CELL_GCM_SURFACE_A8R8G8B8";
|
||||
case CELL_GCM_SURFACE_B8: return "CELL_GCM_SURFACE_B8";
|
||||
case CELL_GCM_SURFACE_G8B8: return "CELL_GCM_SURFACE_G8B8";
|
||||
case CELL_GCM_SURFACE_F_W16Z16Y16X16: return "CELL_GCM_SURFACE_F_W16Z16Y16X16";
|
||||
case CELL_GCM_SURFACE_F_W32Z32Y32X32: return "CELL_GCM_SURFACE_F_W32Z32Y32X32";
|
||||
case CELL_GCM_SURFACE_F_X32: return "CELL_GCM_SURFACE_F_X32";
|
||||
case CELL_GCM_SURFACE_X8B8G8R8_Z8B8G8R8: return "CELL_GCM_SURFACE_X8B8G8R8_Z8B8G8R8";
|
||||
case CELL_GCM_SURFACE_X8B8G8R8_O8B8G8R8: return "CELL_GCM_SURFACE_X8B8G8R8_O8B8G8R8";
|
||||
case CELL_GCM_SURFACE_A8B8G8R8: return "CELL_GCM_SURFACE_A8B8G8R8";
|
||||
case rsx::surface_antialiasing::center_1_sample: return "1 sample centered";
|
||||
case rsx::surface_antialiasing::diagonal_centered_2_samples: return "2 samples diagonal centered";
|
||||
case rsx::surface_antialiasing::square_centered_4_samples: return "4 samples square centered";
|
||||
case rsx::surface_antialiasing::square_rotated_4_samples: return "4 samples diagonal rotated";
|
||||
}
|
||||
return "Error";
|
||||
}
|
||||
|
||||
std::string surface_color_format(u32 format)
|
||||
{
|
||||
switch (rsx::to_surface_color_format(format))
|
||||
{
|
||||
case rsx::surface_color_format::x1r5g5b5_z1r5g5b5: return "CELL_GCM_SURFACE_X1R5G5B5_Z1R5G5B5";
|
||||
case rsx::surface_color_format::x1r5g5b5_o1r5g5b5: return "CELL_GCM_SURFACE_X1R5G5B5_O1R5G5B5";
|
||||
case rsx::surface_color_format::r5g6b5 : return "CELL_GCM_SURFACE_R5G6B5";
|
||||
case rsx::surface_color_format::x8r8g8b8_z8r8g8b8: return "CELL_GCM_SURFACE_X8R8G8B8_Z8R8G8B8";
|
||||
case rsx::surface_color_format::x8r8g8b8_o8r8g8b8: return "CELL_GCM_SURFACE_X8R8G8B8_O8R8G8B8";
|
||||
case rsx::surface_color_format::a8r8g8b8: return "CELL_GCM_SURFACE_A8R8G8B8";
|
||||
case rsx::surface_color_format::b8: return "CELL_GCM_SURFACE_B8";
|
||||
case rsx::surface_color_format::g8b8: return "CELL_GCM_SURFACE_G8B8";
|
||||
case rsx::surface_color_format::w16z16y16x16: return "CELL_GCM_SURFACE_F_W16Z16Y16X16";
|
||||
case rsx::surface_color_format::w32z32y32x32: return "CELL_GCM_SURFACE_F_W32Z32Y32X32";
|
||||
case rsx::surface_color_format::x32: return "CELL_GCM_SURFACE_F_X32";
|
||||
case rsx::surface_color_format::x8b8g8r8_z8b8g8r8: return "CELL_GCM_SURFACE_X8B8G8R8_Z8B8G8R8";
|
||||
case rsx::surface_color_format::x8b8g8r8_o8b8g8r8: return "CELL_GCM_SURFACE_X8B8G8R8_O8B8G8R8";
|
||||
case rsx::surface_color_format::a8b8g8r8: return "CELL_GCM_SURFACE_A8B8G8R8";
|
||||
}
|
||||
return "Error";
|
||||
}
|
||||
|
||||
std::string surface_target(u32 target)
|
||||
{
|
||||
switch (target)
|
||||
switch (rsx::to_surface_target(target))
|
||||
{
|
||||
case CELL_GCM_SURFACE_TARGET_NONE: return "none";
|
||||
case CELL_GCM_SURFACE_TARGET_0: return "surface A";
|
||||
case CELL_GCM_SURFACE_TARGET_1: return "surface B";
|
||||
case CELL_GCM_SURFACE_TARGET_MRT1: return "surfaces A and B";
|
||||
case CELL_GCM_SURFACE_TARGET_MRT2: return "surfaces A, B and C";
|
||||
case CELL_GCM_SURFACE_TARGET_MRT3: return "surfaces A,B, C and D";
|
||||
case rsx::surface_target::none: return "none";
|
||||
case rsx::surface_target::surface_a: return "surface A";
|
||||
case rsx::surface_target::surface_b: return "surface B";
|
||||
case rsx::surface_target::surfaces_a_b: return "surfaces A and B";
|
||||
case rsx::surface_target::surfaces_a_b_c: return "surfaces A, B and C";
|
||||
case rsx::surface_target::surfaces_a_b_c_d: return "surfaces A,B, C and D";
|
||||
}
|
||||
return "Error";
|
||||
}
|
||||
@@ -969,15 +1122,15 @@ namespace
|
||||
|
||||
std::string get_vertex_attribute_format(u8 type)
|
||||
{
|
||||
switch (to_vertex_base_type(type))
|
||||
switch (rsx::to_vertex_base_type(type))
|
||||
{
|
||||
case Vertex_base_type::s1: return "Short";
|
||||
case Vertex_base_type::f: return "Float";
|
||||
case Vertex_base_type::sf: return "Half float";
|
||||
case Vertex_base_type::ub: return "Unsigned byte";
|
||||
case Vertex_base_type::s32k: return "Signed int";
|
||||
case Vertex_base_type::cmp: return "CMP";
|
||||
case Vertex_base_type::ub256: return "UB256";
|
||||
case rsx::vertex_base_type::s1: return "Short";
|
||||
case rsx::vertex_base_type::f: return "Float";
|
||||
case rsx::vertex_base_type::sf: return "Half float";
|
||||
case rsx::vertex_base_type::ub: return "Unsigned byte";
|
||||
case rsx::vertex_base_type::s32k: return "Signed int";
|
||||
case rsx::vertex_base_type::cmp: return "CMP";
|
||||
case rsx::vertex_base_type::ub256: return "UB256";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -995,10 +1148,10 @@ namespace
|
||||
|
||||
std::string index_type(u16 arg)
|
||||
{
|
||||
switch (to_index_array_type(arg))
|
||||
switch (rsx::to_index_array_type(arg))
|
||||
{
|
||||
case Index_array_type::unsigned_16b: return "unsigned short";
|
||||
case Index_array_type::unsigned_32b: return "unsigned int";
|
||||
case rsx::index_array_type::u16: return "unsigned short";
|
||||
case rsx::index_array_type::u32: return "unsigned int";
|
||||
}
|
||||
return "Error";
|
||||
}
|
||||
@@ -1269,6 +1422,31 @@ namespace
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string origin_mode(u32 origin)
|
||||
{
|
||||
switch (rsx::to_window_origin(origin))
|
||||
{
|
||||
case rsx::window_origin::bottom: return "bottom";
|
||||
case rsx::window_origin::top: return "top";
|
||||
}
|
||||
throw EXCEPTION("Wrong origin mode");
|
||||
}
|
||||
|
||||
std::string pixel_center_mode(u32 in)
|
||||
{
|
||||
switch (rsx::to_window_pixel_center(in))
|
||||
{
|
||||
case rsx::window_pixel_center::half: return "half";
|
||||
case rsx::window_pixel_center::integer: return "integer";
|
||||
}
|
||||
throw EXCEPTION("Wrong origin mode");
|
||||
}
|
||||
|
||||
std::string shader_window(u32 arg)
|
||||
{
|
||||
return "Viewport: height = " + std::to_string(arg & 0xFFF) + " origin = " + origin_mode((arg >> 12) & 0xF) + " pixel center = " + pixel_center_mode((arg >> 16) & 0xF);
|
||||
}
|
||||
|
||||
#define OPCODE_RANGE_1(opcode, increment, index, printing_function) \
|
||||
{ (opcode) + (index) * (increment), [](u32 arg) -> std::string { return (printing_function)((index), arg); } },
|
||||
|
||||
@@ -1334,7 +1512,7 @@ namespace
|
||||
{ NV4097_SET_SURFACE_PITCH_Z, [](u32 arg) -> std::string { return "Surface Zeta: Pitch = " + std::to_string(arg); } },
|
||||
{ NV4097_SET_SURFACE_ZETA_OFFSET, [](u32 arg) -> std::string { return "Surface Zeta: Offset = " + ptr_to_string(arg); } },
|
||||
{ NV4097_SET_CONTEXT_DMA_ZETA, [](u32 arg) -> std::string { return "Surface Zeta: DMA mode = " + dma_mode(arg);} },
|
||||
{ NV4097_SET_SURFACE_FORMAT, [](u32 arg) -> std::string { return "Surface: Color format = " + color_surface_format(arg & 0x1F) + " DepthStencil format = " + depth_stencil_surface_format((arg >> 5) & 0x7) + " Anti aliasing =" + std::to_string((arg >> 12) & 0x7); } },
|
||||
{ NV4097_SET_SURFACE_FORMAT, [](u32 arg) -> std::string { return "Surface: Color format = " + surface_color_format(arg & 0x1F) + " DepthStencil format = " + depth_stencil_surface_format((arg >> 5) & 0x7) + " Anti aliasing =" + surface_antialiasing((arg >> 12) & 0x7); } },
|
||||
{ NV4097_SET_SURFACE_CLIP_HORIZONTAL, [](u32 arg) -> std::string { return "Surface: clip x = " + std::to_string(arg & 0xFFFF) + " width = " + std::to_string(arg >> 16); } },
|
||||
{ NV4097_SET_SURFACE_CLIP_VERTICAL, [](u32 arg) -> std::string { return "Surface: clip y = " + std::to_string(arg & 0xFFFF) + " height = " + std::to_string(arg >> 16); } },
|
||||
{ NV4097_SET_SURFACE_COLOR_TARGET, [](u32 arg) -> std::string { return "Surface: Targets " + surface_target(arg); } },
|
||||
@@ -1367,6 +1545,7 @@ namespace
|
||||
{ NV4097_SET_VERTEX_ATTRIB_OUTPUT_MASK, vertex_output_mask },
|
||||
{ NV4097_SET_SHADER_CONTROL, shader_control },
|
||||
{ NV4097_SET_ANTI_ALIASING_CONTROL, anti_aliasing_control },
|
||||
{ NV4097_SET_SHADER_WINDOW, shader_window },
|
||||
{ NV4097_SET_VERTEX_DATA_ARRAY_FORMAT, [](u32 arg) -> std::string { return "Vertex array 0: " + unpack_vertex_format(arg); } },
|
||||
{ NV4097_SET_VERTEX_DATA_ARRAY_FORMAT + 1, [](u32 arg) -> std::string { return "Vertex array 1: " + unpack_vertex_format(arg); } },
|
||||
{ NV4097_SET_VERTEX_DATA_ARRAY_FORMAT + 2, [](u32 arg) -> std::string { return "Vertex array 2: " + unpack_vertex_format(arg); } },
|
||||
|
||||
+113
-71
@@ -23,42 +23,125 @@ enum
|
||||
CELL_GCM_DISPLAY_FREQUENCY_DISABLE = 3,
|
||||
};
|
||||
|
||||
enum class Vertex_base_type : u8
|
||||
namespace rsx
|
||||
{
|
||||
s1, ///< signed byte
|
||||
f, ///< float
|
||||
sf, ///< half float
|
||||
ub, ///< unsigned byte
|
||||
s32k, ///< signed 32bits int
|
||||
cmp, ///< compressed aka X11G11Z10 and always 1. W.
|
||||
ub256,
|
||||
};
|
||||
enum class vertex_base_type : u8
|
||||
{
|
||||
s1, ///< signed byte
|
||||
f, ///< float
|
||||
sf, ///< half float
|
||||
ub, ///< unsigned byte
|
||||
s32k, ///< signed 32bits int
|
||||
cmp, ///< compressed aka X11G11Z10 and always 1. W.
|
||||
ub256,
|
||||
};
|
||||
|
||||
Vertex_base_type to_vertex_base_type(u8 in);
|
||||
vertex_base_type to_vertex_base_type(u8 in);
|
||||
|
||||
enum class Index_array_type : u8
|
||||
{
|
||||
unsigned_32b,
|
||||
unsigned_16b,
|
||||
};
|
||||
enum class index_array_type : u8
|
||||
{
|
||||
u32,
|
||||
u16,
|
||||
};
|
||||
|
||||
Index_array_type to_index_array_type(u8 in);
|
||||
index_array_type to_index_array_type(u8 in);
|
||||
|
||||
enum class Primitive_type : u8
|
||||
{
|
||||
points,
|
||||
lines,
|
||||
line_loop, // line strip with last end being joined with first end.
|
||||
line_strip,
|
||||
triangles,
|
||||
triangle_strip,
|
||||
triangle_fan, // like strip except that every triangle share the first vertex and one instead of 2 from previous triangle.
|
||||
quads,
|
||||
quad_strip,
|
||||
polygon, // convex polygon
|
||||
};
|
||||
enum class primitive_type : u8
|
||||
{
|
||||
points,
|
||||
lines,
|
||||
line_loop, // line strip with last end being joined with first end.
|
||||
line_strip,
|
||||
triangles,
|
||||
triangle_strip,
|
||||
triangle_fan, // like strip except that every triangle share the first vertex and one instead of 2 from previous triangle.
|
||||
quads,
|
||||
quad_strip,
|
||||
polygon, // convex polygon
|
||||
};
|
||||
|
||||
Primitive_type to_primitive_type(u8 in);
|
||||
primitive_type to_primitive_type(u8 in);
|
||||
|
||||
enum class surface_target : u8
|
||||
{
|
||||
none,
|
||||
surface_a,
|
||||
surface_b,
|
||||
surfaces_a_b,
|
||||
surfaces_a_b_c,
|
||||
surfaces_a_b_c_d,
|
||||
};
|
||||
|
||||
surface_target to_surface_target(u8 in);
|
||||
|
||||
enum class surface_depth_format : u8
|
||||
{
|
||||
z16, // unsigned 16 bits depth
|
||||
z24s8, // unsigned 24 bits depth + 8 bits stencil
|
||||
};
|
||||
|
||||
surface_depth_format to_surface_depth_format(u8 in);
|
||||
|
||||
enum class surface_antialiasing : u8
|
||||
{
|
||||
center_1_sample,
|
||||
diagonal_centered_2_samples,
|
||||
square_centered_4_samples,
|
||||
square_rotated_4_samples,
|
||||
};
|
||||
|
||||
surface_antialiasing to_surface_antialiasing(u8 in);
|
||||
|
||||
enum class surface_color_format : u8
|
||||
{
|
||||
x1r5g5b5_z1r5g5b5,
|
||||
x1r5g5b5_o1r5g5b5,
|
||||
r5g6b5,
|
||||
x8r8g8b8_z8r8g8b8,
|
||||
x8r8g8b8_o8r8g8b8,
|
||||
a8r8g8b8,
|
||||
b8,
|
||||
g8b8,
|
||||
w16z16y16x16,
|
||||
w32z32y32x32,
|
||||
x32,
|
||||
x8b8g8r8_z8b8g8r8,
|
||||
x8b8g8r8_o8b8g8r8,
|
||||
a8b8g8r8,
|
||||
};
|
||||
|
||||
surface_color_format to_surface_color_format(u8 in);
|
||||
|
||||
enum class window_origin : u8
|
||||
{
|
||||
top,
|
||||
bottom
|
||||
};
|
||||
|
||||
window_origin to_window_origin(u8 in);
|
||||
|
||||
enum class window_pixel_center : u8
|
||||
{
|
||||
half,
|
||||
integer
|
||||
};
|
||||
|
||||
window_pixel_center to_window_pixel_center(u8 in);
|
||||
|
||||
enum class comparaison_function : u8
|
||||
{
|
||||
never,
|
||||
less,
|
||||
equal,
|
||||
less_or_equal,
|
||||
greater,
|
||||
not_equal,
|
||||
greater_or_equal,
|
||||
always
|
||||
};
|
||||
|
||||
comparaison_function to_comparaison_function(u16 in);
|
||||
}
|
||||
|
||||
enum
|
||||
{
|
||||
@@ -159,44 +242,9 @@ enum
|
||||
// GCM Surface
|
||||
enum
|
||||
{
|
||||
// Surface Target
|
||||
CELL_GCM_SURFACE_TARGET_NONE = 0,
|
||||
CELL_GCM_SURFACE_TARGET_0 = 1,
|
||||
CELL_GCM_SURFACE_TARGET_1 = 2,
|
||||
CELL_GCM_SURFACE_TARGET_MRT1 = 0x13,
|
||||
CELL_GCM_SURFACE_TARGET_MRT2 = 0x17,
|
||||
CELL_GCM_SURFACE_TARGET_MRT3 = 0x1f,
|
||||
|
||||
// Surface Depth
|
||||
CELL_GCM_SURFACE_Z16 = 1,
|
||||
CELL_GCM_SURFACE_Z24S8 = 2,
|
||||
|
||||
// Surface Antialias
|
||||
CELL_GCM_SURFACE_CENTER_1 = 0,
|
||||
CELL_GCM_SURFACE_DIAGONAL_CENTERED_2 = 3,
|
||||
CELL_GCM_SURFACE_SQUARE_CENTERED_4 = 4,
|
||||
CELL_GCM_SURFACE_SQUARE_ROTATED_4 = 5,
|
||||
|
||||
// Surface type
|
||||
CELL_GCM_SURFACE_PITCH = 1,
|
||||
CELL_GCM_SURFACE_SWIZZLE = 2,
|
||||
|
||||
// Surface format
|
||||
CELL_GCM_SURFACE_X1R5G5B5_Z1R5G5B5 = 1,
|
||||
CELL_GCM_SURFACE_X1R5G5B5_O1R5G5B5 = 2,
|
||||
CELL_GCM_SURFACE_R5G6B5 = 3,
|
||||
CELL_GCM_SURFACE_X8R8G8B8_Z8R8G8B8 = 4,
|
||||
CELL_GCM_SURFACE_X8R8G8B8_O8R8G8B8 = 5,
|
||||
CELL_GCM_SURFACE_A8R8G8B8 = 8,
|
||||
CELL_GCM_SURFACE_B8 = 9,
|
||||
CELL_GCM_SURFACE_G8B8 = 10,
|
||||
CELL_GCM_SURFACE_F_W16Z16Y16X16 = 11,
|
||||
CELL_GCM_SURFACE_F_W32Z32Y32X32 = 12,
|
||||
CELL_GCM_SURFACE_F_X32 = 13,
|
||||
CELL_GCM_SURFACE_X8B8G8R8_Z8B8G8R8 = 14,
|
||||
CELL_GCM_SURFACE_X8B8G8R8_O8B8G8R8 = 15,
|
||||
CELL_GCM_SURFACE_A8B8G8R8 = 16,
|
||||
|
||||
};
|
||||
|
||||
enum
|
||||
@@ -463,12 +511,6 @@ enum
|
||||
CELL_GCM_TRUE = 1,
|
||||
CELL_GCM_FALSE = 0,
|
||||
|
||||
CELL_GCM_WINDOW_ORIGIN_TOP = 0,
|
||||
CELL_GCM_WINDOW_ORIGIN_BOTTOM = 1,
|
||||
|
||||
CELL_GCM_WINDOW_PIXEL_CENTER_HALF = 0,
|
||||
CELL_GCM_WINDOW_PIXEL_CENTER_INTEGER = 1,
|
||||
|
||||
CELL_GCM_USER_CLIP_PLANE_DISABLE = 0,
|
||||
CELL_GCM_USER_CLIP_PLANE_ENABLE_LT = 1,
|
||||
CELL_GCM_USER_CLIP_PLANE_ENABLE_GE = 2,
|
||||
|
||||
@@ -40,17 +40,23 @@ std::string getFunctionImpl(FUNCTION f)
|
||||
return "vec4(1., 1., 1., 1.)";
|
||||
case FUNCTION::FUNCTION_FRACT:
|
||||
return "fract($0)";
|
||||
case FUNCTION::FUNCTION_TEXTURE_SAMPLE:
|
||||
case FUNCTION::FUNCTION_TEXTURE_SAMPLE1D:
|
||||
return "texture($t, $0.x)";
|
||||
case FUNCTION::FUNCTION_TEXTURE_SAMPLE1D_PROJ:
|
||||
return "textureProj($t, $0.x, $1.x)"; // Note: $1.x is bias
|
||||
case FUNCTION::FUNCTION_TEXTURE_SAMPLE1D_LOD:
|
||||
return "textureLod($t, $0.x, $1)";
|
||||
case FUNCTION::FUNCTION_TEXTURE_SAMPLE2D:
|
||||
return "texture($t, $0.xy)";
|
||||
case FUNCTION::FUNCTION_TEXTURE_SAMPLE_PROJ:
|
||||
case FUNCTION::FUNCTION_TEXTURE_SAMPLE2D_PROJ:
|
||||
return "textureProj($t, $0.xyz, $1.x)"; // Note: $1.x is bias
|
||||
case FUNCTION::FUNCTION_TEXTURE_SAMPLE_LOD:
|
||||
case FUNCTION::FUNCTION_TEXTURE_SAMPLE2D_LOD:
|
||||
return "textureLod($t, $0.xy, $1)";
|
||||
case FUNCTION::FUNCTION_TEXTURE_CUBE_SAMPLE:
|
||||
case FUNCTION::FUNCTION_TEXTURE_SAMPLECUBE:
|
||||
return "texture($t, $0.xyz)";
|
||||
case FUNCTION::FUNCTION_TEXTURE_CUBE_SAMPLE_PROJ:
|
||||
case FUNCTION::FUNCTION_TEXTURE_SAMPLECUBE_PROJ:
|
||||
return "textureProj($t, $0.xyzw, $1.x)"; // Note: $1.x is bias
|
||||
case FUNCTION::FUNCTION_TEXTURE_CUBE_SAMPLE_LOD:
|
||||
case FUNCTION::FUNCTION_TEXTURE_SAMPLECUBE_LOD:
|
||||
return "textureLod($t, $0.xyz, $1)";
|
||||
case FUNCTION::FUNCTION_DFDX:
|
||||
return "dFdx($0)";
|
||||
@@ -78,3 +84,39 @@ std::string compareFunctionImpl(COMPARE f, const std::string &Op0, const std::st
|
||||
}
|
||||
throw EXCEPTION("Unknow compare function");
|
||||
}
|
||||
|
||||
void insert_glsl_legacy_function(std::ostream& OS)
|
||||
{
|
||||
OS << "vec4 divsq_legacy(vec4 num, vec4 denum)\n";
|
||||
OS << "{\n";
|
||||
OS << " return num / sqrt(max(denum.xxxx, 1.E-10));\n";
|
||||
OS << "}\n";
|
||||
|
||||
OS << "vec4 rcp_legacy(vec4 denum)\n";
|
||||
OS << "{\n";
|
||||
OS << " return 1. / denum;\n";
|
||||
OS << "}\n";
|
||||
|
||||
OS << "vec4 rsq_legacy(vec4 val)\n";
|
||||
OS << "{\n";
|
||||
OS << " return float(1.0 / sqrt(max(val.x, 1.E-10))).xxxx;\n";
|
||||
OS << "}\n\n";
|
||||
|
||||
OS << "vec4 log2_legacy(vec4 val)\n";
|
||||
OS << "{\n";
|
||||
OS << " return log2(max(val.x, 1.E-10)).xxxx;\n";
|
||||
OS << "}\n\n";
|
||||
|
||||
OS << "vec4 lit_legacy(vec4 val)";
|
||||
OS << "{\n";
|
||||
OS << " vec4 clamped_val = val;\n";
|
||||
OS << " clamped_val.x = max(val.x, 0);\n";
|
||||
OS << " clamped_val.y = max(val.y, 0);\n";
|
||||
OS << " vec4 result;\n";
|
||||
OS << " result.x = 1.0;\n";
|
||||
OS << " result.w = 1.;\n";
|
||||
OS << " result.y = clamped_val.x;\n";
|
||||
OS << " result.z = clamped_val.x > 0.0 ? exp(clamped_val.w * log(max(clamped_val.y, 1.E-10))) : 0.0;\n";
|
||||
OS << " return result;\n";
|
||||
OS << "}\n\n";
|
||||
}
|
||||
|
||||
@@ -4,3 +4,4 @@
|
||||
std::string getFloatTypeNameImpl(size_t elementCount);
|
||||
std::string getFunctionImpl(FUNCTION f);
|
||||
std::string compareFunctionImpl(COMPARE f, const std::string &Op0, const std::string &Op1);
|
||||
void insert_glsl_legacy_function(std::ostream& OS);
|
||||
@@ -61,22 +61,39 @@ void GLFragmentDecompilerThread::insertConstants(std::stringstream & OS)
|
||||
{
|
||||
for (const ParamType& PT : m_parr.params[PF_PARAM_UNIFORM])
|
||||
{
|
||||
if (PT.type != "sampler2D")
|
||||
if (PT.type != "sampler1D" &&
|
||||
PT.type != "sampler2D" &&
|
||||
PT.type != "sampler3D" &&
|
||||
PT.type != "samplerCube")
|
||||
continue;
|
||||
for (const ParamItem& PI : PT.items)
|
||||
OS << "uniform " << PT.type << " " << PI.name << ";" << std::endl;
|
||||
|
||||
for (const ParamItem& PI : PT.items)
|
||||
{
|
||||
std::string samplerType = PT.type;
|
||||
int index = atoi(&PI.name.data()[3]);
|
||||
|
||||
if (m_prog.unnormalized_coords & (1 << index))
|
||||
samplerType = "sampler2DRect";
|
||||
|
||||
OS << "uniform " << samplerType << " " << PI.name << ";" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
OS << "layout(std140, binding = 2) uniform FragmentConstantsBuffer" << std::endl;
|
||||
OS << "{" << std::endl;
|
||||
|
||||
for (const ParamType& PT : m_parr.params[PF_PARAM_UNIFORM])
|
||||
{
|
||||
if (PT.type == "sampler2D")
|
||||
if (PT.type == "sampler1D" ||
|
||||
PT.type == "sampler2D" ||
|
||||
PT.type == "sampler3D" ||
|
||||
PT.type == "samplerCube")
|
||||
continue;
|
||||
|
||||
for (const ParamItem& PI : PT.items)
|
||||
OS << " " << PT.type << " " << PI.name << ";" << std::endl;
|
||||
OS << " " << PT.type << " " << PI.name << ";" << std::endl;
|
||||
}
|
||||
|
||||
// A dummy value otherwise it's invalid to create an empty uniform buffer
|
||||
OS << " vec4 void_value;" << std::endl;
|
||||
OS << "};" << std::endl;
|
||||
@@ -84,22 +101,7 @@ void GLFragmentDecompilerThread::insertConstants(std::stringstream & OS)
|
||||
|
||||
void GLFragmentDecompilerThread::insertMainStart(std::stringstream & OS)
|
||||
{
|
||||
// "lib" function
|
||||
// 0.00001 is used as "some non zero very little number"
|
||||
OS << "vec4 divsq_legacy(vec4 num, vec4 denum)\n";
|
||||
OS << "{\n";
|
||||
OS << " return num / sqrt(max(denum.xxxx, 0.00001));\n";
|
||||
OS << "}\n";
|
||||
|
||||
OS << "vec4 rcp_legacy(vec4 denum)\n";
|
||||
OS << "{\n";
|
||||
OS << " return 1. / denum;\n";
|
||||
OS << "}\n";
|
||||
|
||||
OS << "vec4 rsq_legacy(vec4 denum)\n";
|
||||
OS << "{\n";
|
||||
OS << " return 1. / sqrt(max(denum, 0.00001));\n";
|
||||
OS << "}\n";
|
||||
insert_glsl_legacy_function(OS);
|
||||
|
||||
OS << "void main ()" << std::endl;
|
||||
OS << "{" << std::endl;
|
||||
@@ -133,7 +135,17 @@ void GLFragmentDecompilerThread::insertMainEnd(std::stringstream & OS)
|
||||
}
|
||||
|
||||
if (m_ctrl & CELL_GCM_SHADER_CONTROL_DEPTH_EXPORT)
|
||||
OS << ((m_ctrl & CELL_GCM_SHADER_CONTROL_32_BITS_EXPORTS) ? "\tgl_FragDepth = r1.z;\n" : "\tgl_FragDepth = h0.z;\n") << std::endl;
|
||||
{
|
||||
{
|
||||
/** Note: Naruto Shippuden : Ultimate Ninja Storm 2 sets CELL_GCM_SHADER_CONTROL_32_BITS_EXPORTS in a shader
|
||||
* but it writes depth in r1.z and not h2.z.
|
||||
* Maybe there's a different flag for depth ?
|
||||
*/
|
||||
//OS << ((m_ctrl & CELL_GCM_SHADER_CONTROL_32_BITS_EXPORTS) ? "\tgl_FragDepth = r1.z;\n" : "\tgl_FragDepth = h0.z;\n") << std::endl;
|
||||
OS << " gl_FragDepth = r1.z;\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
OS << "}" << std::endl;
|
||||
}
|
||||
|
||||
+219
-136
@@ -9,6 +9,48 @@
|
||||
|
||||
#define DUMP_VERTEX_DATA 0
|
||||
|
||||
namespace
|
||||
{
|
||||
u32 get_max_depth_value(rsx::surface_depth_format format)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case rsx::surface_depth_format::z16: return 0xFFFF;
|
||||
case rsx::surface_depth_format::z24s8: return 0xFFFFFF;
|
||||
}
|
||||
throw EXCEPTION("Unknow depth format");
|
||||
}
|
||||
|
||||
u8 get_pixel_size(rsx::surface_depth_format format)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case rsx::surface_depth_format::z16: return 2;
|
||||
case rsx::surface_depth_format::z24s8: return 4;
|
||||
}
|
||||
throw EXCEPTION("Unknow depth format");
|
||||
}
|
||||
|
||||
u32 to_gl_internal_type(rsx::vertex_base_type type, u8 size)
|
||||
{
|
||||
/**
|
||||
* The buffer texture spec only allows fetches aligned to 8, 16, 32, etc...
|
||||
* This rules out most 3-component formats, except for the 32-wide RGB32F, RGB32I, RGB32UI
|
||||
*/
|
||||
const u32 vec1_types[] = { GL_R16, GL_R32F, GL_R16F, GL_R8, GL_R32I, GL_R16F, GL_R8 };
|
||||
const u32 vec2_types[] = { GL_RG16, GL_RG32F, GL_RG16F, GL_RG8, GL_RG32I, GL_RG16F, GL_RG8 };
|
||||
const u32 vec3_types[] = { GL_RGBA16, GL_RGB32F, GL_RGBA16F, GL_RGBA8, GL_RGB32I, GL_RGBA16F, GL_RGBA8 }; //VEC3 COMPONENTS NOT SUPPORTED!
|
||||
const u32 vec4_types[] = { GL_RGBA16, GL_RGBA32F, GL_RGBA16F, GL_RGBA8, GL_RGBA32I, GL_RGBA16F, GL_RGBA8 };
|
||||
|
||||
const u32* vec_selectors[] = { 0, vec1_types, vec2_types, vec3_types, vec4_types };
|
||||
|
||||
if (type > rsx::vertex_base_type::ub256)
|
||||
throw EXCEPTION("OpenGL error: unknown vertex base type 0x%X.", (u32)type);
|
||||
|
||||
return vec_selectors[size][(int)type];
|
||||
}
|
||||
}
|
||||
|
||||
GLGSRender::GLGSRender() : GSRender(frame_type::OpenGL)
|
||||
{
|
||||
shaders_cache.load(rsx::shader_language::glsl);
|
||||
@@ -97,7 +139,7 @@ void GLGSRender::begin()
|
||||
|
||||
__glcheck glBlendFuncSeparate(sfactor_rgb, dfactor_rgb, sfactor_a, dfactor_a);
|
||||
|
||||
if (m_surface.color_format == CELL_GCM_SURFACE_F_W16Z16Y16X16) //TODO: check another color formats
|
||||
if (m_surface.color_format == rsx::surface_color_format::w16z16y16x16) //TODO: check another color formats
|
||||
{
|
||||
u32 blend_color = rsx::method_registers[NV4097_SET_BLEND_COLOR];
|
||||
u32 blend_color2 = rsx::method_registers[NV4097_SET_BLEND_COLOR2];
|
||||
@@ -295,33 +337,33 @@ void apply_attrib_array(gl::glsl::program& program, int location, const std::vec
|
||||
|
||||
namespace
|
||||
{
|
||||
gl::buffer_pointer::type gl_types(Vertex_base_type type)
|
||||
gl::buffer_pointer::type gl_types(rsx::vertex_base_type type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case Vertex_base_type::s1: return gl::buffer_pointer::type::s16;
|
||||
case Vertex_base_type::f: return gl::buffer_pointer::type::f32;
|
||||
case Vertex_base_type::sf: return gl::buffer_pointer::type::f16;
|
||||
case Vertex_base_type::ub: return gl::buffer_pointer::type::u8;
|
||||
case Vertex_base_type::s32k: return gl::buffer_pointer::type::s32;
|
||||
case Vertex_base_type::cmp: return gl::buffer_pointer::type::s16; // Needs conversion
|
||||
case Vertex_base_type::ub256: gl::buffer_pointer::type::u8;
|
||||
case rsx::vertex_base_type::s1: return gl::buffer_pointer::type::s16;
|
||||
case rsx::vertex_base_type::f: return gl::buffer_pointer::type::f32;
|
||||
case rsx::vertex_base_type::sf: return gl::buffer_pointer::type::f16;
|
||||
case rsx::vertex_base_type::ub: return gl::buffer_pointer::type::u8;
|
||||
case rsx::vertex_base_type::s32k: return gl::buffer_pointer::type::s32;
|
||||
case rsx::vertex_base_type::cmp: return gl::buffer_pointer::type::s16; // Needs conversion
|
||||
case rsx::vertex_base_type::ub256: gl::buffer_pointer::type::u8;
|
||||
}
|
||||
throw EXCEPTION("unknow vertex type");
|
||||
}
|
||||
|
||||
bool gl_normalized(Vertex_base_type type)
|
||||
bool gl_normalized(rsx::vertex_base_type type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case Vertex_base_type::s1:
|
||||
case Vertex_base_type::ub:
|
||||
case Vertex_base_type::cmp:
|
||||
case rsx::vertex_base_type::s1:
|
||||
case rsx::vertex_base_type::ub:
|
||||
case rsx::vertex_base_type::cmp:
|
||||
return true;
|
||||
case Vertex_base_type::f:
|
||||
case Vertex_base_type::sf:
|
||||
case Vertex_base_type::ub256:
|
||||
case Vertex_base_type::s32k:
|
||||
case rsx::vertex_base_type::f:
|
||||
case rsx::vertex_base_type::sf:
|
||||
case rsx::vertex_base_type::ub256:
|
||||
case rsx::vertex_base_type::s32k:
|
||||
return false;
|
||||
}
|
||||
throw EXCEPTION("unknow vertex type");
|
||||
@@ -352,6 +394,12 @@ void GLGSRender::end()
|
||||
int location;
|
||||
if (m_program->uniforms.has_location("tex" + std::to_string(i), &location))
|
||||
{
|
||||
u32 target = GL_TEXTURE_2D;
|
||||
if (textures[i].format() & CELL_GCM_TEXTURE_UN)
|
||||
target = GL_TEXTURE_RECTANGLE;
|
||||
|
||||
m_gl_textures[i].set_target(target);
|
||||
|
||||
__glcheck m_gl_textures[i].init(i, textures[i]);
|
||||
glProgramUniform1i(m_program->id(), location, i);
|
||||
}
|
||||
@@ -374,14 +422,14 @@ void GLGSRender::end()
|
||||
};
|
||||
|
||||
u32 input_mask = rsx::method_registers[NV4097_SET_VERTEX_ATTRIB_INPUT_MASK];
|
||||
m_vao.bind();
|
||||
|
||||
std::vector<u8> vertex_index_array;
|
||||
vertex_draw_count = 0;
|
||||
u32 min_index, max_index;
|
||||
if (draw_command == Draw_command::draw_command_indexed)
|
||||
|
||||
if (draw_command == rsx::draw_command::indexed)
|
||||
{
|
||||
Index_array_type type = to_index_array_type(rsx::method_registers[NV4097_SET_INDEX_ARRAY_DMA] >> 4);
|
||||
rsx::index_array_type type = rsx::to_index_array_type(rsx::method_registers[NV4097_SET_INDEX_ARRAY_DMA] >> 4);
|
||||
u32 type_size = gsl::narrow<u32>(get_index_type_size(type));
|
||||
for (const auto& first_count : first_count_commands)
|
||||
{
|
||||
@@ -392,17 +440,18 @@ void GLGSRender::end()
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case Index_array_type::unsigned_32b:
|
||||
case rsx::index_array_type::u32:
|
||||
std::tie(min_index, max_index) = write_index_array_data_to_buffer_untouched(gsl::span<u32>((u32*)vertex_index_array.data(), vertex_draw_count), first_count_commands);
|
||||
break;
|
||||
case Index_array_type::unsigned_16b:
|
||||
case rsx::index_array_type::u16:
|
||||
std::tie(min_index, max_index) = write_index_array_data_to_buffer_untouched(gsl::span<u16>((u16*)vertex_index_array.data(), vertex_draw_count), first_count_commands);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (draw_command == Draw_command::draw_command_inlined_array)
|
||||
if (draw_command == rsx::draw_command::inlined_array)
|
||||
{
|
||||
vertex_arrays_data.resize(inline_vertex_array.size() * sizeof(u32));
|
||||
write_inline_array_to_buffer(vertex_arrays_data.data());
|
||||
u32 offset = 0;
|
||||
for (int index = 0; index < rsx::limits::vertex_count; ++index)
|
||||
@@ -413,17 +462,30 @@ void GLGSRender::end()
|
||||
continue;
|
||||
|
||||
int location;
|
||||
if (!m_program->attribs.has_location(reg_table[index], &location))
|
||||
if (!m_program->uniforms.has_location(reg_table[index] + "_buffer", &location))
|
||||
continue;
|
||||
|
||||
__glcheck m_program->attribs[location] =
|
||||
(m_vao + offset)
|
||||
.config(gl_types(vertex_info.type), vertex_info.size, gl_normalized(vertex_info.type));
|
||||
const u32 element_size = rsx::get_vertex_type_size_on_host(vertex_info.type, vertex_info.size);
|
||||
const u32 gl_type = to_gl_internal_type(vertex_info.type, vertex_info.size);
|
||||
const u32 data_size = element_size * vertex_draw_count;
|
||||
|
||||
auto &buffer = m_gl_attrib_buffers[index].buffer;
|
||||
auto &texture = m_gl_attrib_buffers[index].texture;
|
||||
|
||||
buffer->data(data_size, nullptr);
|
||||
buffer->sub_data(0, data_size, vertex_arrays_data.data()+offset);
|
||||
|
||||
//Attach buffer to texture
|
||||
texture->copy_from(*buffer, gl_type);
|
||||
|
||||
//Link texture to uniform
|
||||
m_program->uniforms.texture(location, index +rsx::limits::vertex_count, *texture);
|
||||
|
||||
offset += rsx::get_vertex_type_size_on_host(vertex_info.type, vertex_info.size);
|
||||
}
|
||||
}
|
||||
|
||||
if (draw_command == Draw_command::draw_command_array)
|
||||
if (draw_command == rsx::draw_command::array)
|
||||
{
|
||||
for (const auto &first_count : first_count_commands)
|
||||
{
|
||||
@@ -431,7 +493,7 @@ void GLGSRender::end()
|
||||
}
|
||||
}
|
||||
|
||||
if (draw_command == Draw_command::draw_command_array || draw_command == Draw_command::draw_command_indexed)
|
||||
if (draw_command == rsx::draw_command::array || draw_command == rsx::draw_command::indexed)
|
||||
{
|
||||
for (int index = 0; index < rsx::limits::vertex_count; ++index)
|
||||
{
|
||||
@@ -440,7 +502,7 @@ void GLGSRender::end()
|
||||
continue;
|
||||
|
||||
int location;
|
||||
if (!m_program->attribs.has_location(reg_table[index], &location))
|
||||
if (!m_program->uniforms.has_location(reg_table[index]+"_buffer", &location))
|
||||
continue;
|
||||
|
||||
if (vertex_arrays_info[index].size > 0)
|
||||
@@ -452,7 +514,7 @@ void GLGSRender::end()
|
||||
// Fill vertex_array
|
||||
u32 element_size = rsx::get_vertex_type_size_on_host(vertex_info.type, vertex_info.size);
|
||||
vertex_array.resize(vertex_draw_count * element_size);
|
||||
if (draw_command == Draw_command::draw_command_array)
|
||||
if (draw_command == rsx::draw_command::array)
|
||||
{
|
||||
size_t offset = 0;
|
||||
for (const auto &first_count : first_count_commands)
|
||||
@@ -461,7 +523,7 @@ void GLGSRender::end()
|
||||
offset += first_count.second * element_size;
|
||||
}
|
||||
}
|
||||
if (draw_command == Draw_command::draw_command_indexed)
|
||||
if (draw_command == rsx::draw_command::indexed)
|
||||
{
|
||||
vertex_array.resize((max_index + 1) * element_size);
|
||||
write_vertex_array_data_to_buffer(vertex_array.data(), 0, max_index + 1, index, vertex_info);
|
||||
@@ -472,29 +534,48 @@ void GLGSRender::end()
|
||||
vertex_arrays_offsets[index] = gsl::narrow<u32>(position);
|
||||
vertex_arrays_data.resize(position + size);
|
||||
|
||||
memcpy(vertex_arrays_data.data() + position, vertex_array.data(), size);
|
||||
const u32 gl_type = to_gl_internal_type(vertex_info.type, vertex_info.size);
|
||||
const u32 data_size = element_size * vertex_draw_count;
|
||||
|
||||
__glcheck m_program->attribs[location] =
|
||||
(m_vao + vertex_arrays_offsets[index])
|
||||
.config(gl_types(vertex_info.type), vertex_info.size, gl_normalized(vertex_info.type));
|
||||
auto &buffer = m_gl_attrib_buffers[index].buffer;
|
||||
auto &texture = m_gl_attrib_buffers[index].texture;
|
||||
|
||||
buffer->data(data_size, nullptr);
|
||||
buffer->sub_data(0, data_size, vertex_array.data());
|
||||
|
||||
//Attach buffer to texture
|
||||
texture->copy_from(*buffer, gl_type);
|
||||
|
||||
//Link texture to uniform
|
||||
m_program->uniforms.texture(location, index + rsx::limits::vertex_count, *texture);
|
||||
}
|
||||
else if (register_vertex_info[index].size > 0)
|
||||
{
|
||||
//Untested!
|
||||
auto &vertex_data = register_vertex_data[index];
|
||||
auto &vertex_info = register_vertex_info[index];
|
||||
|
||||
switch (vertex_info.type)
|
||||
{
|
||||
case Vertex_base_type::f:
|
||||
switch (register_vertex_info[index].size)
|
||||
{
|
||||
case 1: apply_attrib_array<f32, 1>(*m_program, location, vertex_data); break;
|
||||
case 2: apply_attrib_array<f32, 2>(*m_program, location, vertex_data); break;
|
||||
case 3: apply_attrib_array<f32, 3>(*m_program, location, vertex_data); break;
|
||||
case 4: apply_attrib_array<f32, 4>(*m_program, location, vertex_data); break;
|
||||
}
|
||||
break;
|
||||
case rsx::vertex_base_type::f:
|
||||
{
|
||||
const u32 element_size = rsx::get_vertex_type_size_on_host(vertex_info.type, vertex_info.size);
|
||||
const u32 gl_type = to_gl_internal_type(vertex_info.type, vertex_info.size);
|
||||
const size_t data_size = vertex_data.size();
|
||||
|
||||
auto &buffer = m_gl_attrib_buffers[index].buffer;
|
||||
auto &texture = m_gl_attrib_buffers[index].texture;
|
||||
|
||||
buffer->data(data_size, nullptr);
|
||||
buffer->sub_data(0, data_size, vertex_data.data());
|
||||
|
||||
//Attach buffer to texture
|
||||
texture->copy_from(*buffer, gl_type);
|
||||
|
||||
//Link texture to uniform
|
||||
m_program->uniforms.texture(location, index + rsx::limits::vertex_count, *texture);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
LOG_ERROR(RSX, "bad non array vertex data format (type = %d, size = %d)", vertex_info.type, vertex_info.size);
|
||||
break;
|
||||
@@ -502,17 +583,28 @@ void GLGSRender::end()
|
||||
}
|
||||
}
|
||||
}
|
||||
m_vbo.data(vertex_arrays_data.size(), vertex_arrays_data.data());
|
||||
|
||||
if (draw_command == Draw_command::draw_command_indexed)
|
||||
// glDraw* will fail without at least attrib0 defined if we are on compatibility profile
|
||||
// Someone should really test AMD behaviour here, Nvidia is too permissive. There is no buffer currently bound, but on NV it works ok
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(0, 2, GL_FLOAT, false, 0, 0);
|
||||
|
||||
/**
|
||||
* Validate fails if called right after linking a program because the VS and FS both use textures bound using different
|
||||
* samplers. So far only sampler2D has been largely used, hiding the problem. This call shall also degrade performance further
|
||||
* if used every draw call. Fixes shader validation issues on AMD.
|
||||
*/
|
||||
m_program->validate();
|
||||
|
||||
if (draw_command == rsx::draw_command::indexed)
|
||||
{
|
||||
m_ebo.data(vertex_index_array.size(), vertex_index_array.data());
|
||||
|
||||
Index_array_type indexed_type = to_index_array_type(rsx::method_registers[NV4097_SET_INDEX_ARRAY_DMA] >> 4);
|
||||
rsx::index_array_type indexed_type = rsx::to_index_array_type(rsx::method_registers[NV4097_SET_INDEX_ARRAY_DMA] >> 4);
|
||||
|
||||
if (indexed_type == Index_array_type::unsigned_32b)
|
||||
if (indexed_type == rsx::index_array_type::u32)
|
||||
__glcheck glDrawElements(gl::draw_mode(draw_mode), vertex_draw_count, GL_UNSIGNED_INT, nullptr);
|
||||
if (indexed_type == Index_array_type::unsigned_16b)
|
||||
if (indexed_type == rsx::index_array_type::u16)
|
||||
__glcheck glDrawElements(gl::draw_mode(draw_mode), vertex_draw_count, GL_UNSIGNED_SHORT, nullptr);
|
||||
}
|
||||
else
|
||||
@@ -544,10 +636,10 @@ void GLGSRender::set_viewport()
|
||||
|
||||
u32 shader_window = rsx::method_registers[NV4097_SET_SHADER_WINDOW];
|
||||
|
||||
u8 shader_window_origin = (shader_window >> 12) & 0xf;
|
||||
rsx::window_origin shader_window_origin = rsx::to_window_origin((shader_window >> 12) & 0xf);
|
||||
|
||||
//TODO
|
||||
if (true || shader_window_origin == CELL_GCM_WINDOW_ORIGIN_BOTTOM)
|
||||
if (true || shader_window_origin == rsx::window_origin::bottom)
|
||||
{
|
||||
__glcheck glViewport(viewport_x, viewport_y, viewport_w, viewport_h);
|
||||
__glcheck glScissor(scissor_x, scissor_y, scissor_w, scissor_h);
|
||||
@@ -586,14 +678,25 @@ void GLGSRender::on_init_thread()
|
||||
|
||||
m_vao.array_buffer = m_vbo;
|
||||
m_vao.element_array_buffer = m_ebo;
|
||||
|
||||
for (texture_buffer_pair &attrib_buffer : m_gl_attrib_buffers)
|
||||
{
|
||||
gl::texture *&tex = attrib_buffer.texture;
|
||||
tex = new gl::texture(gl::texture::target::textureBuffer);
|
||||
tex->create();
|
||||
tex->set_target(gl::texture::target::textureBuffer);
|
||||
|
||||
gl::buffer *&buf = attrib_buffer.buffer;
|
||||
buf = new gl::buffer();
|
||||
buf->create();
|
||||
}
|
||||
}
|
||||
|
||||
void GLGSRender::on_exit()
|
||||
{
|
||||
glDisable(GL_VERTEX_PROGRAM_POINT_SIZE);
|
||||
|
||||
//if (m_program)
|
||||
// m_program.remove();
|
||||
m_prog_buffer.clear();
|
||||
|
||||
if (draw_fbo)
|
||||
draw_fbo.remove();
|
||||
@@ -627,6 +730,19 @@ void GLGSRender::on_exit()
|
||||
|
||||
if (m_fragment_constants_buffer)
|
||||
m_fragment_constants_buffer.remove();
|
||||
|
||||
for (texture_buffer_pair &attrib_buffer : m_gl_attrib_buffers)
|
||||
{
|
||||
gl::texture *&tex = attrib_buffer.texture;
|
||||
tex->remove();
|
||||
delete tex;
|
||||
tex = nullptr;
|
||||
|
||||
gl::buffer *&buf = attrib_buffer.buffer;
|
||||
buf->remove();
|
||||
delete buf;
|
||||
buf = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void nv4097_clear_surface(u32 arg, GLGSRender* renderer)
|
||||
@@ -654,8 +770,8 @@ void nv4097_clear_surface(u32 arg, GLGSRender* renderer)
|
||||
|
||||
if (arg & 0x1)
|
||||
{
|
||||
u32 surface_depth_format = (rsx::method_registers[NV4097_SET_SURFACE_FORMAT] >> 5) & 0x7;
|
||||
u32 max_depth_value = surface_depth_format == CELL_GCM_SURFACE_Z16 ? 0x0000ffff : 0x00ffffff;
|
||||
rsx::surface_depth_format surface_depth_format = rsx::to_surface_depth_format((rsx::method_registers[NV4097_SET_SURFACE_FORMAT] >> 5) & 0x7);
|
||||
u32 max_depth_value = get_max_depth_value(surface_depth_format);
|
||||
|
||||
u32 clear_depth = rsx::method_registers[NV4097_SET_ZSTENCIL_CLEAR_VALUE] >> 8;
|
||||
|
||||
@@ -715,37 +831,8 @@ bool GLGSRender::do_method(u32 cmd, u32 arg)
|
||||
bool GLGSRender::load_program()
|
||||
{
|
||||
#if 1
|
||||
RSXVertexProgram vertex_program;
|
||||
u32 transform_program_start = rsx::method_registers[NV4097_SET_TRANSFORM_PROGRAM_START];
|
||||
vertex_program.data.reserve((512 - transform_program_start) * 4);
|
||||
|
||||
for (int i = transform_program_start; i < 512; ++i)
|
||||
{
|
||||
vertex_program.data.resize((i - transform_program_start) * 4 + 4);
|
||||
memcpy(vertex_program.data.data() + (i - transform_program_start) * 4, transform_program + i * 4, 4 * sizeof(u32));
|
||||
|
||||
D3 d3;
|
||||
d3.HEX = transform_program[i * 4 + 3];
|
||||
|
||||
if (d3.end)
|
||||
break;
|
||||
}
|
||||
|
||||
RSXFragmentProgram fragment_program;
|
||||
u32 shader_program = rsx::method_registers[NV4097_SET_SHADER_PROGRAM];
|
||||
fragment_program.offset = shader_program & ~0x3;
|
||||
fragment_program.addr = rsx::get_address(fragment_program.offset, (shader_program & 0x3) - 1);
|
||||
fragment_program.ctrl = rsx::method_registers[NV4097_SET_SHADER_CONTROL];
|
||||
|
||||
for (u32 i = 0; i < rsx::limits::textures_count; ++i)
|
||||
{
|
||||
if (!textures[i].enabled())
|
||||
fragment_program.texture_dimensions.push_back(texture_dimension::texture_dimension_2d);
|
||||
else if (textures[i].cubemap())
|
||||
fragment_program.texture_dimensions.push_back(texture_dimension::texture_dimension_cubemap);
|
||||
else
|
||||
fragment_program.texture_dimensions.push_back(texture_dimension::texture_dimension_2d);
|
||||
}
|
||||
RSXVertexProgram vertex_program = get_current_vertex_program();
|
||||
RSXFragmentProgram fragment_program = get_current_fragment_program();
|
||||
|
||||
__glcheck m_program = &m_prog_buffer.getGraphicPipelineState(vertex_program, fragment_program, nullptr);
|
||||
__glcheck m_program->use();
|
||||
@@ -832,52 +919,52 @@ struct color_format
|
||||
color_swizzle swizzle;
|
||||
};
|
||||
|
||||
color_format surface_color_format_to_gl(int color_format)
|
||||
color_format surface_color_format_to_gl(rsx::surface_color_format color_format)
|
||||
{
|
||||
//color format
|
||||
switch (color_format)
|
||||
{
|
||||
case CELL_GCM_SURFACE_R5G6B5:
|
||||
case rsx::surface_color_format::r5g6b5:
|
||||
return{ gl::texture::type::ushort_5_6_5, gl::texture::format::bgr, false, 3, 2 };
|
||||
|
||||
case CELL_GCM_SURFACE_A8R8G8B8:
|
||||
case rsx::surface_color_format::a8r8g8b8:
|
||||
return{ gl::texture::type::uint_8_8_8_8, gl::texture::format::bgra, false, 4, 1 };
|
||||
|
||||
case CELL_GCM_SURFACE_X8R8G8B8_O8R8G8B8:
|
||||
case rsx::surface_color_format::x8r8g8b8_o8r8g8b8:
|
||||
return{ gl::texture::type::uint_8_8_8_8, gl::texture::format::bgra, false, 4, 1,
|
||||
{ gl::texture::channel::one, gl::texture::channel::r, gl::texture::channel::g, gl::texture::channel::b } };
|
||||
|
||||
case CELL_GCM_SURFACE_F_W16Z16Y16X16:
|
||||
case rsx::surface_color_format::w16z16y16x16:
|
||||
return{ gl::texture::type::f16, gl::texture::format::rgba, true, 4, 2 };
|
||||
|
||||
case CELL_GCM_SURFACE_F_W32Z32Y32X32:
|
||||
case rsx::surface_color_format::w32z32y32x32:
|
||||
return{ gl::texture::type::f32, gl::texture::format::rgba, true, 4, 4 };
|
||||
|
||||
case CELL_GCM_SURFACE_B8:
|
||||
case CELL_GCM_SURFACE_X1R5G5B5_Z1R5G5B5:
|
||||
case CELL_GCM_SURFACE_X1R5G5B5_O1R5G5B5:
|
||||
case CELL_GCM_SURFACE_X8R8G8B8_Z8R8G8B8:
|
||||
case CELL_GCM_SURFACE_G8B8:
|
||||
case CELL_GCM_SURFACE_F_X32:
|
||||
case CELL_GCM_SURFACE_X8B8G8R8_Z8B8G8R8:
|
||||
case CELL_GCM_SURFACE_X8B8G8R8_O8B8G8R8:
|
||||
case CELL_GCM_SURFACE_A8B8G8R8:
|
||||
case rsx::surface_color_format::b8:
|
||||
case rsx::surface_color_format::x1r5g5b5_o1r5g5b5:
|
||||
case rsx::surface_color_format::x1r5g5b5_z1r5g5b5:
|
||||
case rsx::surface_color_format::x8r8g8b8_z8r8g8b8:
|
||||
case rsx::surface_color_format::g8b8:
|
||||
case rsx::surface_color_format::x32:
|
||||
case rsx::surface_color_format::x8b8g8r8_o8b8g8r8:
|
||||
case rsx::surface_color_format::x8b8g8r8_z8b8g8r8:
|
||||
case rsx::surface_color_format::a8b8g8r8:
|
||||
default:
|
||||
LOG_ERROR(RSX, "Surface color buffer: Unsupported surface color format (0x%x)", color_format);
|
||||
return{ gl::texture::type::uint_8_8_8_8, gl::texture::format::bgra, false, 4, 1 };
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<gl::texture::type, gl::texture::format> surface_depth_format_to_gl(int depth_format)
|
||||
std::pair<gl::texture::type, gl::texture::format> surface_depth_format_to_gl(rsx::surface_depth_format depth_format)
|
||||
{
|
||||
switch (depth_format)
|
||||
{
|
||||
case CELL_GCM_SURFACE_Z16:
|
||||
case rsx::surface_depth_format::z16:
|
||||
return std::make_pair(gl::texture::type::ushort, gl::texture::format::depth);
|
||||
|
||||
default:
|
||||
LOG_ERROR(RSX, "Surface depth buffer: Unsupported surface depth format (0x%x)", depth_format);
|
||||
case CELL_GCM_SURFACE_Z24S8:
|
||||
case rsx::surface_depth_format::z24s8:
|
||||
return std::make_pair(gl::texture::type::uint_24_8, gl::texture::format::depth_stencil);
|
||||
//return std::make_pair(gl::texture::type::f32, gl::texture::format::depth);
|
||||
}
|
||||
@@ -926,7 +1013,7 @@ void GLGSRender::init_buffers(bool skip_reading)
|
||||
|
||||
switch (m_surface.depth_format)
|
||||
{
|
||||
case CELL_GCM_SURFACE_Z16:
|
||||
case rsx::surface_depth_format::z16:
|
||||
{
|
||||
__glcheck m_draw_tex_depth_stencil.config()
|
||||
.size({ (int)m_surface.width, (int)m_surface.height })
|
||||
@@ -938,7 +1025,7 @@ void GLGSRender::init_buffers(bool skip_reading)
|
||||
break;
|
||||
}
|
||||
|
||||
case CELL_GCM_SURFACE_Z24S8:
|
||||
case rsx::surface_depth_format::z24s8:
|
||||
{
|
||||
__glcheck m_draw_tex_depth_stencil.config()
|
||||
.size({ (int)m_surface.width, (int)m_surface.height })
|
||||
@@ -950,9 +1037,6 @@ void GLGSRender::init_buffers(bool skip_reading)
|
||||
break;
|
||||
}
|
||||
|
||||
case 0:
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
LOG_ERROR(RSX, "Bad depth format! (%d)", m_surface.depth_format);
|
||||
@@ -972,27 +1056,27 @@ void GLGSRender::init_buffers(bool skip_reading)
|
||||
|
||||
set_viewport();
|
||||
|
||||
switch (rsx::method_registers[NV4097_SET_SURFACE_COLOR_TARGET])
|
||||
switch (rsx::to_surface_target(rsx::method_registers[NV4097_SET_SURFACE_COLOR_TARGET]))
|
||||
{
|
||||
case CELL_GCM_SURFACE_TARGET_NONE: break;
|
||||
case rsx::surface_target::none: break;
|
||||
|
||||
case CELL_GCM_SURFACE_TARGET_0:
|
||||
case rsx::surface_target::surface_a:
|
||||
__glcheck draw_fbo.draw_buffer(draw_fbo.color[0]);
|
||||
break;
|
||||
|
||||
case CELL_GCM_SURFACE_TARGET_1:
|
||||
case rsx::surface_target::surface_b:
|
||||
__glcheck draw_fbo.draw_buffer(draw_fbo.color[1] );
|
||||
break;
|
||||
|
||||
case CELL_GCM_SURFACE_TARGET_MRT1:
|
||||
case rsx::surface_target::surfaces_a_b:
|
||||
__glcheck draw_fbo.draw_buffers({ draw_fbo.color[0], draw_fbo.color[1] });
|
||||
break;
|
||||
|
||||
case CELL_GCM_SURFACE_TARGET_MRT2:
|
||||
case rsx::surface_target::surfaces_a_b_c:
|
||||
__glcheck draw_fbo.draw_buffers({ draw_fbo.color[0], draw_fbo.color[1], draw_fbo.color[2] });
|
||||
break;
|
||||
|
||||
case CELL_GCM_SURFACE_TARGET_MRT3:
|
||||
case rsx::surface_target::surfaces_a_b_c_d:
|
||||
__glcheck draw_fbo.draw_buffers({ draw_fbo.color[0], draw_fbo.color[1], draw_fbo.color[2], draw_fbo.color[3] });
|
||||
break;
|
||||
|
||||
@@ -1070,28 +1154,28 @@ void GLGSRender::read_buffers()
|
||||
}
|
||||
};
|
||||
|
||||
switch (rsx::method_registers[NV4097_SET_SURFACE_COLOR_TARGET])
|
||||
switch (rsx::to_surface_target(rsx::method_registers[NV4097_SET_SURFACE_COLOR_TARGET]))
|
||||
{
|
||||
case CELL_GCM_SURFACE_TARGET_NONE:
|
||||
case rsx::surface_target::none:
|
||||
break;
|
||||
|
||||
case CELL_GCM_SURFACE_TARGET_0:
|
||||
case rsx::surface_target::surface_a:
|
||||
read_color_buffers(0, 1);
|
||||
break;
|
||||
|
||||
case CELL_GCM_SURFACE_TARGET_1:
|
||||
case rsx::surface_target::surface_b:
|
||||
read_color_buffers(1, 1);
|
||||
break;
|
||||
|
||||
case CELL_GCM_SURFACE_TARGET_MRT1:
|
||||
case rsx::surface_target::surfaces_a_b:
|
||||
read_color_buffers(0, 2);
|
||||
break;
|
||||
|
||||
case CELL_GCM_SURFACE_TARGET_MRT2:
|
||||
case rsx::surface_target::surfaces_a_b_c:
|
||||
read_color_buffers(0, 3);
|
||||
break;
|
||||
|
||||
case CELL_GCM_SURFACE_TARGET_MRT3:
|
||||
case rsx::surface_target::surfaces_a_b_c_d:
|
||||
read_color_buffers(0, 4);
|
||||
break;
|
||||
}
|
||||
@@ -1107,8 +1191,7 @@ void GLGSRender::read_buffers()
|
||||
|
||||
auto depth_format = surface_depth_format_to_gl(m_surface.depth_format);
|
||||
|
||||
int pixel_size = m_surface.depth_format == CELL_GCM_SURFACE_Z16 ? 2 : 4;
|
||||
|
||||
int pixel_size = get_pixel_size(m_surface.depth_format);
|
||||
gl::buffer pbo_depth;
|
||||
|
||||
__glcheck pbo_depth.create(m_surface.width * m_surface.height * pixel_size);
|
||||
@@ -1116,7 +1199,7 @@ void GLGSRender::read_buffers()
|
||||
{
|
||||
u32 depth_address = rsx::get_address(rsx::method_registers[NV4097_SET_SURFACE_ZETA_OFFSET], rsx::method_registers[NV4097_SET_CONTEXT_DMA_ZETA]);
|
||||
|
||||
if (m_surface.depth_format == CELL_GCM_SURFACE_Z16)
|
||||
if (m_surface.depth_format == rsx::surface_depth_format::z16)
|
||||
{
|
||||
u16 *dst = (u16*)pixels;
|
||||
const be_t<u16>* src = vm::ps3::_ptr<u16>(depth_address);
|
||||
@@ -1202,28 +1285,28 @@ void GLGSRender::write_buffers()
|
||||
}
|
||||
};
|
||||
|
||||
switch (rsx::method_registers[NV4097_SET_SURFACE_COLOR_TARGET])
|
||||
switch (rsx::to_surface_target(rsx::method_registers[NV4097_SET_SURFACE_COLOR_TARGET]))
|
||||
{
|
||||
case CELL_GCM_SURFACE_TARGET_NONE:
|
||||
case rsx::surface_target::none:
|
||||
break;
|
||||
|
||||
case CELL_GCM_SURFACE_TARGET_0:
|
||||
case rsx::surface_target::surface_a:
|
||||
write_color_buffers(0, 1);
|
||||
break;
|
||||
|
||||
case CELL_GCM_SURFACE_TARGET_1:
|
||||
case rsx::surface_target::surface_b:
|
||||
write_color_buffers(1, 1);
|
||||
break;
|
||||
|
||||
case CELL_GCM_SURFACE_TARGET_MRT1:
|
||||
case rsx::surface_target::surfaces_a_b:
|
||||
write_color_buffers(0, 2);
|
||||
break;
|
||||
|
||||
case CELL_GCM_SURFACE_TARGET_MRT2:
|
||||
case rsx::surface_target::surfaces_a_b_c:
|
||||
write_color_buffers(0, 3);
|
||||
break;
|
||||
|
||||
case CELL_GCM_SURFACE_TARGET_MRT3:
|
||||
case rsx::surface_target::surfaces_a_b_c_d:
|
||||
write_color_buffers(0, 4);
|
||||
break;
|
||||
}
|
||||
@@ -1241,7 +1324,7 @@ void GLGSRender::write_buffers()
|
||||
|
||||
gl::buffer pbo_depth;
|
||||
|
||||
int pixel_size = m_surface.depth_format == CELL_GCM_SURFACE_Z16 ? 2 : 4;
|
||||
int pixel_size = get_pixel_size(m_surface.depth_format);
|
||||
|
||||
__glcheck pbo_depth.create(m_surface.width * m_surface.height * pixel_size);
|
||||
__glcheck m_draw_tex_depth_stencil.copy_to(pbo_depth, depth_format.second, depth_format.first);
|
||||
@@ -1250,7 +1333,7 @@ void GLGSRender::write_buffers()
|
||||
{
|
||||
u32 depth_address = rsx::get_address(rsx::method_registers[NV4097_SET_SURFACE_ZETA_OFFSET], rsx::method_registers[NV4097_SET_CONTEXT_DMA_ZETA]);
|
||||
|
||||
if (m_surface.depth_format == CELL_GCM_SURFACE_Z16)
|
||||
if (m_surface.depth_format == rsx::surface_depth_format::z16)
|
||||
{
|
||||
const u16 *src = (const u16*)pixels;
|
||||
be_t<u16>* dst = vm::ps3::_ptr<u16>(depth_address);
|
||||
|
||||
@@ -22,6 +22,13 @@ private:
|
||||
|
||||
rsx::surface_info m_surface;
|
||||
|
||||
struct texture_buffer_pair
|
||||
{
|
||||
gl::texture *texture;
|
||||
gl::buffer *buffer;
|
||||
}
|
||||
m_gl_attrib_buffers[rsx::limits::vertex_count];
|
||||
|
||||
public:
|
||||
gl::fbo draw_fbo;
|
||||
|
||||
|
||||
@@ -166,6 +166,10 @@ OPENGL_PROC(PFNGLCHECKFRAMEBUFFERSTATUSPROC, CheckFramebufferStatus);
|
||||
|
||||
OPENGL_PROC(PFNGLBINDBUFFERBASEPROC, BindBufferBase);
|
||||
|
||||
//Texture Buffers
|
||||
OPENGL_PROC(PFNGLTEXBUFFERPROC, TexBuffer);
|
||||
OPENGL_PROC(PFNGLTEXTUREBUFFERRANGEEXTPROC, TextureBufferRangeEXT);
|
||||
|
||||
//KHR_debug
|
||||
OPENGL_PROC(PFNGLDEBUGMESSAGECONTROLARBPROC, DebugMessageControlARB);
|
||||
OPENGL_PROC(PFNGLDEBUGMESSAGEINSERTARBPROC, DebugMessageInsertARB);
|
||||
|
||||
@@ -27,7 +27,7 @@ std::string GLVertexDecompilerThread::compareFunction(COMPARE f, const std::stri
|
||||
|
||||
void GLVertexDecompilerThread::insertHeader(std::stringstream &OS)
|
||||
{
|
||||
OS << "#version 420" << std::endl << std::endl;
|
||||
OS << "#version 430" << std::endl << std::endl;
|
||||
OS << "layout(std140, binding = 0) uniform ScaleOffsetBuffer" << std::endl;
|
||||
OS << "{" << std::endl;
|
||||
OS << " mat4 scaleOffsetMat;" << std::endl;
|
||||
@@ -36,10 +36,33 @@ void GLVertexDecompilerThread::insertHeader(std::stringstream &OS)
|
||||
|
||||
void GLVertexDecompilerThread::insertInputs(std::stringstream & OS, const std::vector<ParamType>& inputs)
|
||||
{
|
||||
for (const ParamType PT : inputs)
|
||||
std::vector<std::tuple<size_t, std::string>> input_data;
|
||||
for (const ParamType &PT : inputs)
|
||||
{
|
||||
for (const ParamItem &PI : PT.items)
|
||||
OS << /*"layout(location = " << PI.location << ") "*/ "in " << PT.type << " " << PI.name << ";" << std::endl;
|
||||
{
|
||||
input_data.push_back(std::make_tuple(PI.location, PI.name));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Its is important that the locations are in the order that vertex attributes are expected.
|
||||
* If order is not adhered to, channels may be swapped leading to corruption
|
||||
*/
|
||||
|
||||
std::sort(input_data.begin(), input_data.end());
|
||||
|
||||
int location = 1;
|
||||
for (const std::tuple<size_t, std::string> item : input_data)
|
||||
{
|
||||
for (const ParamType &PT : inputs)
|
||||
{
|
||||
for (const ParamItem &PI : PT.items)
|
||||
{
|
||||
if (PI.name == std::get<1>(item))
|
||||
OS << "layout(location=" << location++ << ")" << " uniform samplerBuffer" << " " << PI.name << "_buffer;" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,9 +124,42 @@ void GLVertexDecompilerThread::insertOutputs(std::stringstream & OS, const std::
|
||||
}
|
||||
}
|
||||
|
||||
void add_input(std::stringstream & OS, const ParamItem &PI, const std::vector<rsx_vertex_input> &inputs)
|
||||
{
|
||||
for (const auto &real_input : inputs)
|
||||
{
|
||||
if (real_input.location != PI.location)
|
||||
continue;
|
||||
|
||||
if (!real_input.is_array)
|
||||
{
|
||||
OS << " vec4 " << PI.name << " = texelFetch(" << PI.name << "_buffer, 0);" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
if (real_input.frequency > 1)
|
||||
{
|
||||
if (real_input.is_modulo)
|
||||
{
|
||||
OS << " vec4 " << PI.name << "= texelFetch(" << PI.name << "_buffer, gl_VertexID %" << real_input.frequency << ");" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
OS << " vec4 " << PI.name << "= texelFetch(" << PI.name << "_buffer, gl_VertexID /" << real_input.frequency << ");" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
OS << " vec4 " << PI.name << "= texelFetch(" << PI.name << "_buffer, gl_VertexID);" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
OS << " vec4 " << PI.name << " = vec4(0., 0., 0., 1.);" << std::endl;
|
||||
}
|
||||
|
||||
void GLVertexDecompilerThread::insertMainStart(std::stringstream & OS)
|
||||
{
|
||||
insert_glsl_legacy_function(OS);
|
||||
|
||||
OS << "void main()" << std::endl;
|
||||
OS << "{" << std::endl;
|
||||
|
||||
@@ -118,6 +174,12 @@ void GLVertexDecompilerThread::insertMainStart(std::stringstream & OS)
|
||||
OS << ";" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
for (const ParamType &PT : m_parr.params[PF_PARAM_IN])
|
||||
{
|
||||
for (const ParamItem &PI : PT.items)
|
||||
add_input(OS, PI, rsx_vertex_program.rsx_vertex_inputs);
|
||||
}
|
||||
}
|
||||
|
||||
void GLVertexDecompilerThread::insertMainEnd(std::stringstream & OS)
|
||||
|
||||
@@ -19,10 +19,13 @@ protected:
|
||||
virtual void insertOutputs(std::stringstream &OS, const std::vector<ParamType> &outputs) override;
|
||||
virtual void insertMainStart(std::stringstream &OS) override;
|
||||
virtual void insertMainEnd(std::stringstream &OS) override;
|
||||
|
||||
const RSXVertexProgram &rsx_vertex_program;
|
||||
public:
|
||||
GLVertexDecompilerThread(const RSXVertexProgram &prog, std::string& shader, ParamArray& parr)
|
||||
: VertexProgramDecompiler(prog)
|
||||
, m_shader(shader)
|
||||
, rsx_vertex_program(prog)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -5,20 +5,20 @@ namespace gl
|
||||
{
|
||||
const fbo screen{};
|
||||
|
||||
GLenum draw_mode(Primitive_type in)
|
||||
GLenum draw_mode(rsx::primitive_type in)
|
||||
{
|
||||
switch (in)
|
||||
{
|
||||
case Primitive_type::points: return GL_POINTS;
|
||||
case Primitive_type::lines: return GL_LINES;
|
||||
case Primitive_type::line_loop: return GL_LINE_LOOP;
|
||||
case Primitive_type::line_strip: return GL_LINE_STRIP;
|
||||
case Primitive_type::triangles: return GL_TRIANGLES;
|
||||
case Primitive_type::triangle_strip: return GL_TRIANGLE_STRIP;
|
||||
case Primitive_type::triangle_fan: return GL_TRIANGLE_FAN;
|
||||
case Primitive_type::quads: return GL_QUADS;
|
||||
case Primitive_type::quad_strip: return GL_QUAD_STRIP;
|
||||
case Primitive_type::polygon: return GL_POLYGON;
|
||||
case rsx::primitive_type::points: return GL_POINTS;
|
||||
case rsx::primitive_type::lines: return GL_LINES;
|
||||
case rsx::primitive_type::line_loop: return GL_LINE_LOOP;
|
||||
case rsx::primitive_type::line_strip: return GL_LINE_STRIP;
|
||||
case rsx::primitive_type::triangles: return GL_TRIANGLES;
|
||||
case rsx::primitive_type::triangle_strip: return GL_TRIANGLE_STRIP;
|
||||
case rsx::primitive_type::triangle_fan: return GL_TRIANGLE_FAN;
|
||||
case rsx::primitive_type::quads: return GL_QUADS;
|
||||
case rsx::primitive_type::quad_strip: return GL_QUAD_STRIP;
|
||||
case rsx::primitive_type::polygon: return GL_POLYGON;
|
||||
}
|
||||
throw new EXCEPTION("unknow primitive type");
|
||||
}
|
||||
@@ -97,74 +97,74 @@ namespace gl
|
||||
__glcheck glDrawBuffers((GLsizei)ids.size(), ids.data());
|
||||
}
|
||||
|
||||
void fbo::draw_arrays(Primitive_type mode, GLsizei count, GLint first) const
|
||||
void fbo::draw_arrays(rsx::primitive_type mode, GLsizei count, GLint first) const
|
||||
{
|
||||
save_binding_state save(*this);
|
||||
__glcheck glDrawArrays(draw_mode(mode), first, count);
|
||||
}
|
||||
|
||||
void fbo::draw_arrays(const buffer& buffer, Primitive_type mode, GLsizei count, GLint first) const
|
||||
void fbo::draw_arrays(const buffer& buffer, rsx::primitive_type mode, GLsizei count, GLint first) const
|
||||
{
|
||||
buffer.bind(buffer::target::array);
|
||||
draw_arrays(mode, count, first);
|
||||
}
|
||||
|
||||
void fbo::draw_arrays(const vao& buffer, Primitive_type mode, GLsizei count, GLint first) const
|
||||
void fbo::draw_arrays(const vao& buffer, rsx::primitive_type mode, GLsizei count, GLint first) const
|
||||
{
|
||||
buffer.bind();
|
||||
draw_arrays(mode, count, first);
|
||||
}
|
||||
|
||||
void fbo::draw_elements(Primitive_type mode, GLsizei count, indices_type type, const GLvoid *indices) const
|
||||
void fbo::draw_elements(rsx::primitive_type mode, GLsizei count, indices_type type, const GLvoid *indices) const
|
||||
{
|
||||
save_binding_state save(*this);
|
||||
__glcheck glDrawElements(draw_mode(mode), count, (GLenum)type, indices);
|
||||
}
|
||||
|
||||
void fbo::draw_elements(const buffer& buffer, Primitive_type mode, GLsizei count, indices_type type, const GLvoid *indices) const
|
||||
void fbo::draw_elements(const buffer& buffer, rsx::primitive_type mode, GLsizei count, indices_type type, const GLvoid *indices) const
|
||||
{
|
||||
buffer.bind(buffer::target::array);
|
||||
__glcheck glDrawElements(draw_mode(mode), count, (GLenum)type, indices);
|
||||
}
|
||||
|
||||
void fbo::draw_elements(Primitive_type mode, GLsizei count, indices_type type, const buffer& indices, size_t indices_buffer_offset) const
|
||||
void fbo::draw_elements(rsx::primitive_type mode, GLsizei count, indices_type type, const buffer& indices, size_t indices_buffer_offset) const
|
||||
{
|
||||
indices.bind(buffer::target::element_array);
|
||||
__glcheck glDrawElements(draw_mode(mode), count, (GLenum)type, (GLvoid*)indices_buffer_offset);
|
||||
}
|
||||
|
||||
void fbo::draw_elements(const buffer& buffer_, Primitive_type mode, GLsizei count, indices_type type, const buffer& indices, size_t indices_buffer_offset) const
|
||||
void fbo::draw_elements(const buffer& buffer_, rsx::primitive_type mode, GLsizei count, indices_type type, const buffer& indices, size_t indices_buffer_offset) const
|
||||
{
|
||||
buffer_.bind(buffer::target::array);
|
||||
draw_elements(mode, count, type, indices, indices_buffer_offset);
|
||||
}
|
||||
|
||||
void fbo::draw_elements(Primitive_type mode, GLsizei count, const GLubyte *indices) const
|
||||
void fbo::draw_elements(rsx::primitive_type mode, GLsizei count, const GLubyte *indices) const
|
||||
{
|
||||
draw_elements(mode, count, indices_type::ubyte, indices);
|
||||
}
|
||||
|
||||
void fbo::draw_elements(const buffer& buffer, Primitive_type mode, GLsizei count, const GLubyte *indices) const
|
||||
void fbo::draw_elements(const buffer& buffer, rsx::primitive_type mode, GLsizei count, const GLubyte *indices) const
|
||||
{
|
||||
draw_elements(buffer, mode, count, indices_type::ubyte, indices);
|
||||
}
|
||||
|
||||
void fbo::draw_elements(Primitive_type mode, GLsizei count, const GLushort *indices) const
|
||||
void fbo::draw_elements(rsx::primitive_type mode, GLsizei count, const GLushort *indices) const
|
||||
{
|
||||
draw_elements(mode, count, indices_type::ushort, indices);
|
||||
}
|
||||
|
||||
void fbo::draw_elements(const buffer& buffer, Primitive_type mode, GLsizei count, const GLushort *indices) const
|
||||
void fbo::draw_elements(const buffer& buffer, rsx::primitive_type mode, GLsizei count, const GLushort *indices) const
|
||||
{
|
||||
draw_elements(buffer, mode, count, indices_type::ushort, indices);
|
||||
}
|
||||
|
||||
void fbo::draw_elements(Primitive_type mode, GLsizei count, const GLuint *indices) const
|
||||
void fbo::draw_elements(rsx::primitive_type mode, GLsizei count, const GLuint *indices) const
|
||||
{
|
||||
draw_elements(mode, count, indices_type::uint, indices);
|
||||
}
|
||||
|
||||
void fbo::draw_elements(const buffer& buffer, Primitive_type mode, GLsizei count, const GLuint *indices) const
|
||||
void fbo::draw_elements(const buffer& buffer, rsx::primitive_type mode, GLsizei count, const GLuint *indices) const
|
||||
{
|
||||
draw_elements(buffer, mode, count, indices_type::uint, indices);
|
||||
}
|
||||
|
||||
@@ -830,7 +830,8 @@ namespace gl
|
||||
{
|
||||
texture1D = GL_TEXTURE_1D,
|
||||
texture2D = GL_TEXTURE_2D,
|
||||
texture3D = GL_TEXTURE_3D
|
||||
texture3D = GL_TEXTURE_3D,
|
||||
textureBuffer = GL_TEXTURE_BUFFER
|
||||
};
|
||||
|
||||
enum class channel_type
|
||||
@@ -863,9 +864,10 @@ namespace gl
|
||||
GLenum pname;
|
||||
switch (new_binding.get_target())
|
||||
{
|
||||
case target::texture1D: pname = GL_TEXTURE_1D_BINDING_EXT; break;
|
||||
case target::texture2D: pname = GL_TEXTURE_2D_BINDING_EXT; break;
|
||||
case target::texture3D: pname = GL_TEXTURE_3D_BINDING_EXT; break;
|
||||
case target::texture1D: pname = GL_TEXTURE_BINDING_1D; break;
|
||||
case target::texture2D: pname = GL_TEXTURE_BINDING_2D; break;
|
||||
case target::texture3D: pname = GL_TEXTURE_BINDING_3D; break;
|
||||
case target::textureBuffer: pname = GL_TEXTURE_BINDING_BUFFER; break;
|
||||
}
|
||||
|
||||
glGetIntegerv(pname, &m_last_binding);
|
||||
@@ -1131,6 +1133,29 @@ namespace gl
|
||||
__glcheck glTexSubImage2D((GLenum)get_target(), level(), 0, 0, width(), height(), (GLenum)format, (GLenum)type, src);
|
||||
}
|
||||
|
||||
void copy_from(buffer &buf, u32 gl_format_type, u32 offset, u32 length)
|
||||
{
|
||||
if (get_target() != target::textureBuffer)
|
||||
throw EXCEPTION("OpenGL error: texture cannot copy from buffer");
|
||||
|
||||
if (!offset)
|
||||
{
|
||||
copy_from(buf, gl_format_type);
|
||||
return;
|
||||
}
|
||||
|
||||
if (glTextureBufferRangeEXT == nullptr)
|
||||
throw EXCEPTION("OpenGL error: partial buffer access for textures is unsupported on your system");
|
||||
|
||||
__glcheck glTextureBufferRangeEXT(id(), (GLenum)target::textureBuffer, gl_format_type, buf.id(), offset, length);
|
||||
}
|
||||
|
||||
void copy_from(buffer &buf, u32 gl_format_type)
|
||||
{
|
||||
save_binding_state save(*this);
|
||||
__glcheck glTexBuffer((GLenum)target::textureBuffer, gl_format_type, buf.id());
|
||||
}
|
||||
|
||||
void copy_from(const buffer& buf, texture::format format, texture::type type, class pixel_unpack_settings pixel_settings)
|
||||
{
|
||||
buffer::save_binding_state save_buffer(buffer::target::pixel_unpack, buf);
|
||||
@@ -1380,7 +1405,7 @@ namespace gl
|
||||
settings& border_color(color4f value);
|
||||
};
|
||||
|
||||
GLenum draw_mode(Primitive_type in);
|
||||
GLenum draw_mode(rsx::primitive_type in);
|
||||
|
||||
enum class indices_type
|
||||
{
|
||||
@@ -1523,20 +1548,20 @@ namespace gl
|
||||
void draw_buffer(const attachment& buffer) const;
|
||||
void draw_buffers(const std::initializer_list<attachment>& indexes) const;
|
||||
|
||||
void draw_arrays(Primitive_type mode, GLsizei count, GLint first = 0) const;
|
||||
void draw_arrays(const buffer& buffer, Primitive_type mode, GLsizei count, GLint first = 0) const;
|
||||
void draw_arrays(const vao& buffer, Primitive_type mode, GLsizei count, GLint first = 0) const;
|
||||
void draw_arrays(rsx::primitive_type mode, GLsizei count, GLint first = 0) const;
|
||||
void draw_arrays(const buffer& buffer, rsx::primitive_type mode, GLsizei count, GLint first = 0) const;
|
||||
void draw_arrays(const vao& buffer, rsx::primitive_type mode, GLsizei count, GLint first = 0) const;
|
||||
|
||||
void draw_elements(Primitive_type mode, GLsizei count, indices_type type, const GLvoid *indices) const;
|
||||
void draw_elements(const buffer& buffer, Primitive_type mode, GLsizei count, indices_type type, const GLvoid *indices) const;
|
||||
void draw_elements(Primitive_type mode, GLsizei count, indices_type type, const buffer& indices, size_t indices_buffer_offset = 0) const;
|
||||
void draw_elements(const buffer& buffer_, Primitive_type mode, GLsizei count, indices_type type, const buffer& indices, size_t indices_buffer_offset = 0) const;
|
||||
void draw_elements(Primitive_type mode, GLsizei count, const GLubyte *indices) const;
|
||||
void draw_elements(const buffer& buffer, Primitive_type mode, GLsizei count, const GLubyte *indices) const;
|
||||
void draw_elements(Primitive_type mode, GLsizei count, const GLushort *indices) const;
|
||||
void draw_elements(const buffer& buffer, Primitive_type mode, GLsizei count, const GLushort *indices) const;
|
||||
void draw_elements(Primitive_type mode, GLsizei count, const GLuint *indices) const;
|
||||
void draw_elements(const buffer& buffer, Primitive_type mode, GLsizei count, const GLuint *indices) const;
|
||||
void draw_elements(rsx::primitive_type mode, GLsizei count, indices_type type, const GLvoid *indices) const;
|
||||
void draw_elements(const buffer& buffer, rsx::primitive_type mode, GLsizei count, indices_type type, const GLvoid *indices) const;
|
||||
void draw_elements(rsx::primitive_type mode, GLsizei count, indices_type type, const buffer& indices, size_t indices_buffer_offset = 0) const;
|
||||
void draw_elements(const buffer& buffer_, rsx::primitive_type mode, GLsizei count, indices_type type, const buffer& indices, size_t indices_buffer_offset = 0) const;
|
||||
void draw_elements(rsx::primitive_type mode, GLsizei count, const GLubyte *indices) const;
|
||||
void draw_elements(const buffer& buffer, rsx::primitive_type mode, GLsizei count, const GLubyte *indices) const;
|
||||
void draw_elements(rsx::primitive_type mode, GLsizei count, const GLushort *indices) const;
|
||||
void draw_elements(const buffer& buffer, rsx::primitive_type mode, GLsizei count, const GLushort *indices) const;
|
||||
void draw_elements(rsx::primitive_type mode, GLsizei count, const GLuint *indices) const;
|
||||
void draw_elements(const buffer& buffer, rsx::primitive_type mode, GLsizei count, const GLuint *indices) const;
|
||||
|
||||
void clear(buffers buffers_) const;
|
||||
void clear(buffers buffers_, color4f color_value, double depth_value, u8 stencil_value) const;
|
||||
@@ -2071,7 +2096,6 @@ namespace gl
|
||||
void make()
|
||||
{
|
||||
link();
|
||||
validate();
|
||||
}
|
||||
|
||||
uint id() const
|
||||
|
||||
+136
-160
@@ -5,6 +5,7 @@
|
||||
#include "../RSXThread.h"
|
||||
#include "../RSXTexture.h"
|
||||
#include "../rsx_utils.h"
|
||||
#include "../Common/TextureUtils.h"
|
||||
|
||||
namespace rsx
|
||||
{
|
||||
@@ -89,6 +90,63 @@ namespace rsx
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
u16 texture::get_pitch_modifier(u32 format)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case CELL_GCM_TEXTURE_COMPRESSED_HILO8:
|
||||
case CELL_GCM_TEXTURE_COMPRESSED_HILO_S8:
|
||||
default:
|
||||
LOG_ERROR(RSX, "Unimplemented Texture format : 0x%x", format);
|
||||
return 0;
|
||||
case ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN) & CELL_GCM_TEXTURE_COMPRESSED_B8R8_G8R8:
|
||||
case ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN) & CELL_GCM_TEXTURE_COMPRESSED_R8B8_R8G8:
|
||||
return 4;
|
||||
case CELL_GCM_TEXTURE_B8:
|
||||
return 1;
|
||||
case CELL_GCM_TEXTURE_COMPRESSED_DXT1:
|
||||
case CELL_GCM_TEXTURE_COMPRESSED_DXT23:
|
||||
case CELL_GCM_TEXTURE_COMPRESSED_DXT45:
|
||||
return 0;
|
||||
case CELL_GCM_TEXTURE_A1R5G5B5:
|
||||
case CELL_GCM_TEXTURE_A4R4G4B4:
|
||||
case CELL_GCM_TEXTURE_R5G6B5:
|
||||
case CELL_GCM_TEXTURE_G8B8:
|
||||
case CELL_GCM_TEXTURE_R6G5B5:
|
||||
case CELL_GCM_TEXTURE_DEPTH16:
|
||||
case CELL_GCM_TEXTURE_DEPTH16_FLOAT:
|
||||
case CELL_GCM_TEXTURE_X16:
|
||||
case CELL_GCM_TEXTURE_R5G5B5A1:
|
||||
case CELL_GCM_TEXTURE_D1R5G5B5:
|
||||
return 2;
|
||||
case CELL_GCM_TEXTURE_A8R8G8B8:
|
||||
case CELL_GCM_TEXTURE_X32_FLOAT:
|
||||
case CELL_GCM_TEXTURE_Y16_X16_FLOAT:
|
||||
case CELL_GCM_TEXTURE_D8R8G8B8:
|
||||
case CELL_GCM_TEXTURE_COMPRESSED_B8R8_G8R8:
|
||||
case CELL_GCM_TEXTURE_COMPRESSED_R8B8_R8G8:
|
||||
case CELL_GCM_TEXTURE_DEPTH24_D8:
|
||||
case CELL_GCM_TEXTURE_DEPTH24_D8_FLOAT:
|
||||
case CELL_GCM_TEXTURE_Y16_X16:
|
||||
return 4;
|
||||
case CELL_GCM_TEXTURE_W16_Z16_Y16_X16_FLOAT:
|
||||
return 8;
|
||||
case CELL_GCM_TEXTURE_W32_Z32_Y32_X32_FLOAT:
|
||||
return 16;
|
||||
}
|
||||
}
|
||||
|
||||
bool texture::mandates_expansion(u32 format)
|
||||
{
|
||||
/**
|
||||
* If a texture behaves differently when uploaded directly vs when uploaded via texutils methods, it should be added here.
|
||||
*/
|
||||
if (format == CELL_GCM_TEXTURE_A1R5G5B5)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void texture::init(int index, rsx::texture& tex)
|
||||
{
|
||||
if (!m_id)
|
||||
@@ -110,8 +168,6 @@ namespace rsx
|
||||
u32 format = full_format & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN);
|
||||
bool is_swizzled = !!(~full_format & CELL_GCM_TEXTURE_LN);
|
||||
|
||||
const u8* pixels = vm::ps3::_ptr<u8>(texaddr);
|
||||
u8 *unswizzledPixels;
|
||||
static const GLint glRemapStandard[4] = { GL_ALPHA, GL_RED, GL_GREEN, GL_BLUE };
|
||||
// NOTE: This must be in ARGB order in all forms below.
|
||||
const GLint *glRemap = glRemapStandard;
|
||||
@@ -119,14 +175,36 @@ namespace rsx
|
||||
::gl::pixel_pack_settings().apply();
|
||||
::gl::pixel_unpack_settings().apply();
|
||||
|
||||
u32 pitch = tex.pitch();
|
||||
u32 aligned_pitch = tex.pitch();
|
||||
|
||||
size_t texture_data_sz = get_placed_texture_storage_size(tex, 256);
|
||||
std::vector<u8> data_upload_buf(texture_data_sz);
|
||||
u8* texture_data = data_upload_buf.data();
|
||||
u32 block_sz = get_pitch_modifier(format);
|
||||
|
||||
if (is_swizzled || mandates_expansion(format))
|
||||
{
|
||||
aligned_pitch = align(aligned_pitch, 256);
|
||||
upload_placed_texture(tex, 256, texture_data);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
texture_data = vm::ps3::_ptr<u8>(texaddr);
|
||||
}
|
||||
|
||||
if (block_sz)
|
||||
aligned_pitch /= block_sz;
|
||||
else
|
||||
aligned_pitch = 0;
|
||||
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, aligned_pitch);
|
||||
|
||||
switch (format)
|
||||
{
|
||||
case CELL_GCM_TEXTURE_B8: // One 8-bit fixed-point number
|
||||
{
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.width(), tex.height(), 0, GL_BLUE, GL_UNSIGNED_BYTE, pixels);
|
||||
glTexImage2D(m_target, 0, GL_RGBA, tex.width(), tex.height(), 0, GL_BLUE, GL_UNSIGNED_BYTE, texture_data);
|
||||
|
||||
static const GLint swizzleMaskB8[] = { GL_BLUE, GL_BLUE, GL_BLUE, GL_BLUE };
|
||||
glRemap = swizzleMaskB8;
|
||||
@@ -135,19 +213,13 @@ namespace rsx
|
||||
|
||||
case CELL_GCM_TEXTURE_A1R5G5B5:
|
||||
{
|
||||
glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_TRUE);
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch / 2);
|
||||
|
||||
// TODO: texture swizzling
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.width(), tex.height(), 0, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, pixels);
|
||||
glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
|
||||
glTexImage2D(m_target, 0, GL_RGBA, tex.width(), tex.height(), 0, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, texture_data);
|
||||
break;
|
||||
}
|
||||
|
||||
case CELL_GCM_TEXTURE_A4R4G4B4:
|
||||
{
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch / 2);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.width(), tex.height(), 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, pixels);
|
||||
glTexImage2D(m_target, 0, GL_RGBA, tex.width(), tex.height(), 0, GL_BGRA, GL_UNSIGNED_SHORT_4_4_4_4, texture_data);
|
||||
|
||||
// We read it in as R4G4B4A4, so we need to remap each component.
|
||||
static const GLint swizzleMaskA4R4G4B4[] = { GL_BLUE, GL_ALPHA, GL_RED, GL_GREEN };
|
||||
@@ -157,67 +229,43 @@ namespace rsx
|
||||
|
||||
case CELL_GCM_TEXTURE_R5G6B5:
|
||||
{
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch / 2);
|
||||
LOG_WARNING(RSX, "CELL_GCM_R5G6B5 texture. Watch out for corruption due to swapped color channels!");
|
||||
glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_TRUE);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tex.width(), tex.height(), 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, pixels);
|
||||
glTexImage2D(m_target, 0, GL_RGB, tex.width(), tex.height(), 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, texture_data);
|
||||
glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
|
||||
break;
|
||||
}
|
||||
|
||||
case CELL_GCM_TEXTURE_A8R8G8B8:
|
||||
{
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch / 4);
|
||||
|
||||
if (is_swizzled)
|
||||
{
|
||||
u32 *src, *dst;
|
||||
u16 height = tex.height();
|
||||
u16 width = tex.width();
|
||||
|
||||
unswizzledPixels = (u8*)malloc(width * height * 4);
|
||||
src = (u32*)pixels;
|
||||
dst = (u32*)unswizzledPixels;
|
||||
|
||||
if ((height & (height - 1)) || (width & (width - 1)))
|
||||
{
|
||||
LOG_ERROR(RSX, "Swizzle Texture: Width or height not power of 2! (h=%d,w=%d).", height, width);
|
||||
}
|
||||
|
||||
rsx::convert_linear_swizzle<u32>(src, dst, width, height, true);
|
||||
}
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.width(), tex.height(), 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, is_swizzled ? unswizzledPixels : pixels);
|
||||
glTexImage2D(m_target, 0, GL_RGBA, tex.width(), tex.height(), 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, texture_data);
|
||||
break;
|
||||
}
|
||||
|
||||
case CELL_GCM_TEXTURE_COMPRESSED_DXT1: // Compressed 4x4 pixels into 8 bytes
|
||||
{
|
||||
u32 size = ((tex.width() + 3) / 4) * ((tex.height() + 3) / 4) * 8;
|
||||
|
||||
glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, tex.width(), tex.height(), 0, size, pixels);
|
||||
glCompressedTexImage2D(m_target, 0, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, tex.width(), tex.height(), 0, size, texture_data);
|
||||
break;
|
||||
}
|
||||
|
||||
case CELL_GCM_TEXTURE_COMPRESSED_DXT23: // Compressed 4x4 pixels into 16 bytes
|
||||
{
|
||||
u32 size = ((tex.width() + 3) / 4) * ((tex.height() + 3) / 4) * 16;
|
||||
|
||||
glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, tex.width(), tex.height(), 0, size, pixels);
|
||||
glCompressedTexImage2D(m_target, 0, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, tex.width(), tex.height(), 0, size, texture_data);
|
||||
}
|
||||
break;
|
||||
|
||||
case CELL_GCM_TEXTURE_COMPRESSED_DXT45: // Compressed 4x4 pixels into 16 bytes
|
||||
{
|
||||
u32 size = ((tex.width() + 3) / 4) * ((tex.height() + 3) / 4) * 16;
|
||||
|
||||
glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, tex.width(), tex.height(), 0, size, pixels);
|
||||
glCompressedTexImage2D(m_target, 0, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, tex.width(), tex.height(), 0, size, texture_data);
|
||||
break;
|
||||
}
|
||||
|
||||
case CELL_GCM_TEXTURE_G8B8:
|
||||
{
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch / 2);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.width(), tex.height(), 0, GL_RG, GL_UNSIGNED_BYTE, pixels);
|
||||
glTexImage2D(m_target, 0, GL_RGBA, tex.width(), tex.height(), 0, GL_RG, GL_UNSIGNED_BYTE, texture_data);
|
||||
|
||||
static const GLint swizzleMaskG8B8[] = { GL_RED, GL_GREEN, GL_RED, GL_GREEN };
|
||||
glRemap = swizzleMaskG8B8;
|
||||
@@ -226,60 +274,39 @@ namespace rsx
|
||||
|
||||
case CELL_GCM_TEXTURE_R6G5B5:
|
||||
{
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch / 2);
|
||||
|
||||
// TODO: Probably need to actually unswizzle if is_swizzled.
|
||||
const u32 numPixels = tex.width() * tex.height();
|
||||
unswizzledPixels = (u8 *)malloc(numPixels * 4);
|
||||
// TODO: Speed.
|
||||
for (u32 i = 0; i < numPixels; ++i) {
|
||||
u16 c = reinterpret_cast<const be_t<u16> *>(pixels)[i];
|
||||
unswizzledPixels[i * 4 + 0] = convert_6_to_8((c >> 10) & 0x3F);
|
||||
unswizzledPixels[i * 4 + 1] = convert_5_to_8((c >> 5) & 0x1F);
|
||||
unswizzledPixels[i * 4 + 2] = convert_5_to_8((c >> 0) & 0x1F);
|
||||
unswizzledPixels[i * 4 + 3] = 255;
|
||||
}
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.width(), tex.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, unswizzledPixels);
|
||||
|
||||
free(unswizzledPixels);
|
||||
glTexImage2D(m_target, 0, GL_RGBA, tex.width(), tex.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, texture_data);
|
||||
break;
|
||||
}
|
||||
|
||||
case CELL_GCM_TEXTURE_DEPTH24_D8: // 24-bit unsigned fixed-point number and 8 bits of garbage
|
||||
{
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch / 4);
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, tex.width(), tex.height(), 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, pixels);
|
||||
glTexImage2D(m_target, 0, GL_DEPTH_COMPONENT24, tex.width(), tex.height(), 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, texture_data);
|
||||
break;
|
||||
}
|
||||
|
||||
case CELL_GCM_TEXTURE_DEPTH24_D8_FLOAT: // 24-bit unsigned float and 8 bits of garbage
|
||||
{
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch / 4);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, tex.width(), tex.height(), 0, GL_DEPTH_COMPONENT, GL_FLOAT, pixels);
|
||||
glTexImage2D(m_target, 0, GL_DEPTH_COMPONENT24, tex.width(), tex.height(), 0, GL_DEPTH_COMPONENT, GL_FLOAT, texture_data);
|
||||
break;
|
||||
}
|
||||
|
||||
case CELL_GCM_TEXTURE_DEPTH16: // 16-bit unsigned fixed-point number
|
||||
{
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch / 2);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, tex.width(), tex.height(), 0, GL_DEPTH_COMPONENT, GL_SHORT, pixels);
|
||||
glTexImage2D(m_target, 0, GL_DEPTH_COMPONENT16, tex.width(), tex.height(), 0, GL_DEPTH_COMPONENT, GL_SHORT, texture_data);
|
||||
break;
|
||||
}
|
||||
|
||||
case CELL_GCM_TEXTURE_DEPTH16_FLOAT: // 16-bit unsigned float
|
||||
{
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch / 2);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, tex.width(), tex.height(), 0, GL_DEPTH_COMPONENT, GL_FLOAT, pixels);
|
||||
glTexImage2D(m_target, 0, GL_DEPTH_COMPONENT16, tex.width(), tex.height(), 0, GL_DEPTH_COMPONENT, GL_FLOAT, texture_data);
|
||||
break;
|
||||
}
|
||||
|
||||
case CELL_GCM_TEXTURE_X16: // A 16-bit fixed-point number
|
||||
{
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch / 2);
|
||||
LOG_WARNING(RSX, "CELL_GCM_X16 texture. Watch out for corruption due to swapped color channels!");
|
||||
glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_TRUE);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.width(), tex.height(), 0, GL_RED, GL_UNSIGNED_SHORT, pixels);
|
||||
glTexImage2D(m_target, 0, GL_RGBA, tex.width(), tex.height(), 0, GL_RED, GL_UNSIGNED_SHORT, texture_data);
|
||||
glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
|
||||
|
||||
static const GLint swizzleMaskX16[] = { GL_RED, GL_ONE, GL_RED, GL_ONE };
|
||||
@@ -289,10 +316,11 @@ namespace rsx
|
||||
|
||||
case CELL_GCM_TEXTURE_Y16_X16: // Two 16-bit fixed-point numbers
|
||||
{
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch / 4);
|
||||
LOG_WARNING(RSX, "CELL_GCM_Y16_X16 texture. Watch out for corruption due to swapped color channels!");
|
||||
glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_TRUE);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.width(), tex.height(), 0, GL_RG, GL_UNSIGNED_SHORT, pixels);
|
||||
glTexImage2D(m_target, 0, GL_RGBA, tex.width(), tex.height(), 0, GL_RG, GL_UNSIGNED_SHORT, texture_data);
|
||||
glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
|
||||
|
||||
static const GLint swizzleMaskX32_Y16_X16[] = { GL_GREEN, GL_RED, GL_GREEN, GL_RED };
|
||||
glRemap = swizzleMaskX32_Y16_X16;
|
||||
break;
|
||||
@@ -300,35 +328,34 @@ namespace rsx
|
||||
|
||||
case CELL_GCM_TEXTURE_R5G5B5A1:
|
||||
{
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch / 2);
|
||||
LOG_WARNING(RSX, "CELL_GCM_R5G6B5A1 texture. Watch out for corruption due to swapped color channels!");
|
||||
glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_TRUE);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.width(), tex.height(), 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, pixels);
|
||||
glTexImage2D(m_target, 0, GL_RGBA, tex.width(), tex.height(), 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, texture_data);
|
||||
glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
|
||||
break;
|
||||
}
|
||||
|
||||
case CELL_GCM_TEXTURE_W16_Z16_Y16_X16_FLOAT: // Four fp16 values
|
||||
{
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch / 8);
|
||||
LOG_WARNING(RSX, "CELL_GCM_W16_Z16_Y16_X16_FLOAT texture. Watch out for corruption due to swapped color channels!");
|
||||
glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_TRUE);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.width(), tex.height(), 0, GL_RGBA, GL_HALF_FLOAT, pixels);
|
||||
glTexImage2D(m_target, 0, GL_RGBA, tex.width(), tex.height(), 0, GL_RGBA, GL_HALF_FLOAT, texture_data);
|
||||
glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
|
||||
break;
|
||||
}
|
||||
|
||||
case CELL_GCM_TEXTURE_W32_Z32_Y32_X32_FLOAT: // Four fp32 values
|
||||
{
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch / 16);
|
||||
LOG_WARNING(RSX, "CELL_GCM_W32_Z32_Y32_X32_FLOAT texture. Watch out for corruption due to swapped color channels!");
|
||||
glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_TRUE);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.width(), tex.height(), 0, GL_RGBA, GL_FLOAT, pixels);
|
||||
glTexImage2D(m_target, 0, GL_RGBA, tex.width(), tex.height(), 0, GL_RGBA, GL_FLOAT, texture_data);
|
||||
glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
|
||||
break;
|
||||
}
|
||||
|
||||
case CELL_GCM_TEXTURE_X32_FLOAT: // One 32-bit floating-point number
|
||||
{
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch / 4);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.width(), tex.height(), 0, GL_RED, GL_FLOAT, pixels);
|
||||
glTexImage2D(m_target, 0, GL_RGBA, tex.width(), tex.height(), 0, GL_RED, GL_FLOAT, texture_data);
|
||||
|
||||
static const GLint swizzleMaskX32_FLOAT[] = { GL_RED, GL_ONE, GL_ONE, GL_ONE };
|
||||
glRemap = swizzleMaskX32_FLOAT;
|
||||
@@ -337,11 +364,11 @@ namespace rsx
|
||||
|
||||
case CELL_GCM_TEXTURE_D1R5G5B5:
|
||||
{
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch / 2);
|
||||
LOG_WARNING(RSX, "CELL_GCM_D1R5G5B5 texture. Watch out for corruption due to swapped color channels!");
|
||||
glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_TRUE);
|
||||
|
||||
// TODO: Texture swizzling
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.width(), tex.height(), 0, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, pixels);
|
||||
glTexImage2D(m_target, 0, GL_RGBA, tex.width(), tex.height(), 0, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, texture_data);
|
||||
|
||||
static const GLint swizzleMaskX32_D1R5G5B5[] = { GL_ONE, GL_RED, GL_GREEN, GL_BLUE };
|
||||
glRemap = swizzleMaskX32_D1R5G5B5;
|
||||
@@ -352,8 +379,7 @@ namespace rsx
|
||||
|
||||
case CELL_GCM_TEXTURE_D8R8G8B8: // 8 bits of garbage and three unsigned 8-bit fixed-point numbers
|
||||
{
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch / 4);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.width(), tex.height(), 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, pixels);
|
||||
glTexImage2D(m_target, 0, GL_RGBA, tex.width(), tex.height(), 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, texture_data);
|
||||
|
||||
static const GLint swizzleMaskX32_D8R8G8B8[] = { GL_ONE, GL_RED, GL_GREEN, GL_BLUE };
|
||||
glRemap = swizzleMaskX32_D8R8G8B8;
|
||||
@@ -363,9 +389,9 @@ namespace rsx
|
||||
|
||||
case CELL_GCM_TEXTURE_Y16_X16_FLOAT: // Two fp16 values
|
||||
{
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch / 4);
|
||||
LOG_WARNING(RSX, "CELL_GCM_Y16_X16_FLOAT texture. Watch out for corruption due to swapped color channels!");
|
||||
glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_TRUE);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.width(), tex.height(), 0, GL_RG, GL_HALF_FLOAT, pixels);
|
||||
glTexImage2D(m_target, 0, GL_RGBA, tex.width(), tex.height(), 0, GL_RG, GL_HALF_FLOAT, texture_data);
|
||||
glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
|
||||
|
||||
static const GLint swizzleMaskX32_Y16_X16_FLOAT[] = { GL_RED, GL_GREEN, GL_RED, GL_GREEN };
|
||||
@@ -374,54 +400,9 @@ namespace rsx
|
||||
}
|
||||
|
||||
case ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN) & CELL_GCM_TEXTURE_COMPRESSED_B8R8_G8R8:
|
||||
{
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch / 4);
|
||||
|
||||
const u32 numPixels = tex.width() * tex.height();
|
||||
unswizzledPixels = (u8 *)malloc(numPixels * 4);
|
||||
// TODO: Speed.
|
||||
for (u32 i = 0; i < numPixels; i += 2)
|
||||
{
|
||||
unswizzledPixels[i * 4 + 0 + 0] = pixels[i * 2 + 3];
|
||||
unswizzledPixels[i * 4 + 0 + 1] = pixels[i * 2 + 2];
|
||||
unswizzledPixels[i * 4 + 0 + 2] = pixels[i * 2 + 0];
|
||||
unswizzledPixels[i * 4 + 0 + 3] = 255;
|
||||
|
||||
// The second pixel is the same, except for red.
|
||||
unswizzledPixels[i * 4 + 4 + 0] = pixels[i * 2 + 1];
|
||||
unswizzledPixels[i * 4 + 4 + 1] = pixels[i * 2 + 2];
|
||||
unswizzledPixels[i * 4 + 4 + 2] = pixels[i * 2 + 0];
|
||||
unswizzledPixels[i * 4 + 4 + 3] = 255;
|
||||
}
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.width(), tex.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, unswizzledPixels);
|
||||
free(unswizzledPixels);
|
||||
break;
|
||||
}
|
||||
|
||||
case ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN) & CELL_GCM_TEXTURE_COMPRESSED_R8B8_R8G8:
|
||||
{
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch / 4);
|
||||
|
||||
const u32 numPixels = tex.width() * tex.height();
|
||||
unswizzledPixels = (u8 *)malloc(numPixels * 4);
|
||||
// TODO: Speed.
|
||||
for (u32 i = 0; i < numPixels; i += 2)
|
||||
{
|
||||
unswizzledPixels[i * 4 + 0 + 0] = pixels[i * 2 + 2];
|
||||
unswizzledPixels[i * 4 + 0 + 1] = pixels[i * 2 + 3];
|
||||
unswizzledPixels[i * 4 + 0 + 2] = pixels[i * 2 + 1];
|
||||
unswizzledPixels[i * 4 + 0 + 3] = 255;
|
||||
|
||||
// The second pixel is the same, except for red.
|
||||
unswizzledPixels[i * 4 + 4 + 0] = pixels[i * 2 + 0];
|
||||
unswizzledPixels[i * 4 + 4 + 1] = pixels[i * 2 + 3];
|
||||
unswizzledPixels[i * 4 + 4 + 2] = pixels[i * 2 + 1];
|
||||
unswizzledPixels[i * 4 + 4 + 3] = 255;
|
||||
}
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.width(), tex.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, unswizzledPixels);
|
||||
free(unswizzledPixels);
|
||||
glTexImage2D(m_target, 0, GL_RGBA, tex.width(), tex.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, texture_data);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -432,8 +413,8 @@ namespace rsx
|
||||
}
|
||||
}
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, tex.mipmap() - 1);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, tex.mipmap() > 1);
|
||||
glTexParameteri(m_target, GL_TEXTURE_MAX_LEVEL, tex.mipmap() - 1);
|
||||
glTexParameteri(m_target, GL_GENERATE_MIPMAP, tex.mipmap() > 1);
|
||||
|
||||
if (format != CELL_GCM_TEXTURE_B8 && format != CELL_GCM_TEXTURE_X16 && format != CELL_GCM_TEXTURE_X32_FLOAT)
|
||||
{
|
||||
@@ -442,48 +423,43 @@ namespace rsx
|
||||
u8 remap_g = (tex.remap() >> 4) & 0x3;
|
||||
u8 remap_b = (tex.remap() >> 6) & 0x3;
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, glRemap[remap_a]);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, glRemap[remap_r]);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, glRemap[remap_g]);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, glRemap[remap_b]);
|
||||
glTexParameteri(m_target, GL_TEXTURE_SWIZZLE_A, glRemap[remap_a]);
|
||||
glTexParameteri(m_target, GL_TEXTURE_SWIZZLE_R, glRemap[remap_r]);
|
||||
glTexParameteri(m_target, GL_TEXTURE_SWIZZLE_G, glRemap[remap_g]);
|
||||
glTexParameteri(m_target, GL_TEXTURE_SWIZZLE_B, glRemap[remap_b]);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, glRemap[0]);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, glRemap[1]);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, glRemap[2]);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, glRemap[3]);
|
||||
glTexParameteri(m_target, GL_TEXTURE_SWIZZLE_A, glRemap[0]);
|
||||
glTexParameteri(m_target, GL_TEXTURE_SWIZZLE_R, glRemap[1]);
|
||||
glTexParameteri(m_target, GL_TEXTURE_SWIZZLE_G, glRemap[2]);
|
||||
glTexParameteri(m_target, GL_TEXTURE_SWIZZLE_B, glRemap[3]);
|
||||
}
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, gl_wrap(tex.wrap_s()));
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, gl_wrap(tex.wrap_t()));
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, gl_wrap(tex.wrap_r()));
|
||||
glTexParameteri(m_target, GL_TEXTURE_WRAP_S, gl_wrap(tex.wrap_s()));
|
||||
glTexParameteri(m_target, GL_TEXTURE_WRAP_T, gl_wrap(tex.wrap_t()));
|
||||
glTexParameteri(m_target, GL_TEXTURE_WRAP_R, gl_wrap(tex.wrap_r()));
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, gl_tex_zfunc[tex.zfunc()]);
|
||||
glTexParameteri(m_target, GL_TEXTURE_COMPARE_FUNC, gl_tex_zfunc[tex.zfunc()]);
|
||||
|
||||
glTexEnvi(GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, (GLint)tex.bias());
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, (tex.min_lod() >> 8));
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, (tex.max_lod() >> 8));
|
||||
glTexParameteri(m_target, GL_TEXTURE_MIN_LOD, (tex.min_lod() >> 8));
|
||||
glTexParameteri(m_target, GL_TEXTURE_MAX_LOD, (tex.max_lod() >> 8));
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_tex_min_filter[tex.min_filter()]);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_tex_mag_filter[tex.mag_filter()]);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, max_aniso(tex.max_aniso()));
|
||||
|
||||
if (is_swizzled && format == CELL_GCM_TEXTURE_A8R8G8B8)
|
||||
{
|
||||
free(unswizzledPixels);
|
||||
}
|
||||
glTexParameteri(m_target, GL_TEXTURE_MIN_FILTER, gl_tex_min_filter[tex.min_filter()]);
|
||||
glTexParameteri(m_target, GL_TEXTURE_MAG_FILTER, gl_tex_mag_filter[tex.mag_filter()]);
|
||||
glTexParameterf(m_target, GL_TEXTURE_MAX_ANISOTROPY_EXT, max_aniso(tex.max_aniso()));
|
||||
}
|
||||
|
||||
void texture::bind()
|
||||
{
|
||||
glBindTexture(GL_TEXTURE_2D, m_id);
|
||||
glBindTexture(m_target, m_id);
|
||||
}
|
||||
|
||||
void texture::unbind()
|
||||
{
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glBindTexture(m_target, 0);
|
||||
}
|
||||
|
||||
void texture::remove()
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include "OpenGL.h"
|
||||
|
||||
namespace rsx
|
||||
{
|
||||
@@ -8,6 +9,7 @@ namespace rsx
|
||||
class texture
|
||||
{
|
||||
u32 m_id = 0;
|
||||
u32 m_target = GL_TEXTURE_2D;
|
||||
|
||||
public:
|
||||
void create();
|
||||
@@ -35,10 +37,25 @@ namespace rsx
|
||||
}
|
||||
|
||||
void init(int index, rsx::texture& tex);
|
||||
|
||||
/**
|
||||
* If a format is marked as mandating expansion, any request to have the data uploaded to the GPU shall require that the pixel data
|
||||
* be decoded/expanded fully, regardless of whether the input is swizzled. This is because some formats behave differently when swizzled pixel data
|
||||
* is decoded and when data is fed directly, usually byte order is not the same. Forcing decoding/expanding fixes this but slows performance.
|
||||
*/
|
||||
static bool mandates_expansion(u32 format);
|
||||
|
||||
/**
|
||||
* The pitch modifier changes the pitch value supplied by the rsx::texture by supplying a suitable divisor or 0 if no change is needed.
|
||||
* The modified value, if any, is then used to supply to GL the UNPACK_ROW_LENGTH for the texture data to be supplied.
|
||||
*/
|
||||
static u16 get_pitch_modifier(u32 format);
|
||||
|
||||
void bind();
|
||||
void unbind();
|
||||
void remove();
|
||||
|
||||
void set_target(u32 target) { m_target = target; }
|
||||
u32 id() const;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#pragma once
|
||||
#include "GCM.h"
|
||||
|
||||
enum
|
||||
{
|
||||
@@ -204,26 +205,54 @@ static const std::string rsx_fp_op_names[] =
|
||||
"NULL", "BRK", "CAL", "IFE", "LOOP", "REP", "RET"
|
||||
};
|
||||
|
||||
enum class texture_dimension
|
||||
enum class texture_dimension : u8
|
||||
{
|
||||
texture_dimension_2d,
|
||||
texture_dimension_2d_array,
|
||||
texture_dimension_cubemap,
|
||||
texture_dimension_1d = 0,
|
||||
texture_dimension_2d = 1,
|
||||
texture_dimension_cubemap = 2,
|
||||
texture_dimension_3d = 3,
|
||||
};
|
||||
|
||||
struct RSXFragmentProgram
|
||||
{
|
||||
u32 size;
|
||||
u32 addr;
|
||||
void *addr;
|
||||
u32 offset;
|
||||
u32 ctrl;
|
||||
std::vector<texture_dimension> texture_dimensions;
|
||||
u16 unnormalized_coords;
|
||||
rsx::comparaison_function alpha_func;
|
||||
bool front_back_color_enabled : 1;
|
||||
bool back_color_diffuse_output : 1;
|
||||
bool back_color_specular_output : 1;
|
||||
u32 texture_dimensions;
|
||||
rsx::window_origin origin_mode;
|
||||
rsx::window_pixel_center pixel_center_mode;
|
||||
u16 height;
|
||||
|
||||
texture_dimension get_texture_dimension(u8 id) const
|
||||
{
|
||||
return (texture_dimension)((texture_dimensions >> (id * 2)) & 0x3);
|
||||
}
|
||||
|
||||
void set_texture_dimension(const std::array<texture_dimension, 16> &dimensions)
|
||||
{
|
||||
size_t id = 0;
|
||||
for (const texture_dimension &dim : dimensions)
|
||||
{
|
||||
texture_dimensions &= ~(0x3 << (id * 2));
|
||||
u8 d = (u8)dim;
|
||||
texture_dimensions |= ((d & 0x3) << (id * 2));
|
||||
id++;
|
||||
}
|
||||
}
|
||||
|
||||
RSXFragmentProgram()
|
||||
: size(0)
|
||||
, addr(0)
|
||||
, offset(0)
|
||||
, ctrl(0)
|
||||
, unnormalized_coords(0)
|
||||
, texture_dimensions(0)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
@@ -202,12 +202,12 @@ namespace rsx
|
||||
|
||||
u16 texture::depth() const
|
||||
{
|
||||
return method_registers[NV4097_SET_TEXTURE_CONTROL3] >> 20;
|
||||
return method_registers[NV4097_SET_TEXTURE_CONTROL3 + m_index] >> 20;
|
||||
}
|
||||
|
||||
u32 texture::pitch() const
|
||||
{
|
||||
return method_registers[NV4097_SET_TEXTURE_CONTROL3] & 0xfffff;
|
||||
return method_registers[NV4097_SET_TEXTURE_CONTROL3 + m_index] & 0xfffff;
|
||||
}
|
||||
|
||||
void vertex_texture::init(u8 index)
|
||||
@@ -386,11 +386,11 @@ namespace rsx
|
||||
|
||||
u16 vertex_texture::depth() const
|
||||
{
|
||||
return method_registers[NV4097_SET_VERTEX_TEXTURE_CONTROL3] >> 20;
|
||||
return method_registers[NV4097_SET_VERTEX_TEXTURE_CONTROL3 + (m_index * 8)] >> 20;
|
||||
}
|
||||
|
||||
u32 vertex_texture::pitch() const
|
||||
{
|
||||
return method_registers[NV4097_SET_VERTEX_TEXTURE_CONTROL3] & 0xfffff;
|
||||
return method_registers[NV4097_SET_VERTEX_TEXTURE_CONTROL3 + (m_index * 8)] & 0xfffff;
|
||||
}
|
||||
}
|
||||
+219
-49
@@ -19,6 +19,8 @@ frame_capture_data frame_debug;
|
||||
|
||||
namespace rsx
|
||||
{
|
||||
std::function<bool(u32 addr, bool is_writing)> g_access_violation_handler;
|
||||
|
||||
std::string shaders_cache::path_to_root()
|
||||
{
|
||||
return fs::get_executable_dir() + "data/";
|
||||
@@ -120,11 +122,11 @@ namespace rsx
|
||||
return res;
|
||||
}
|
||||
|
||||
u32 get_vertex_type_size_on_host(Vertex_base_type type, u32 size)
|
||||
u32 get_vertex_type_size_on_host(vertex_base_type type, u32 size)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case Vertex_base_type::s1:
|
||||
case vertex_base_type::s1:
|
||||
switch (size)
|
||||
{
|
||||
case 1:
|
||||
@@ -135,8 +137,8 @@ namespace rsx
|
||||
return sizeof(u16) * 4;
|
||||
}
|
||||
throw new EXCEPTION("Wrong vector size");
|
||||
case Vertex_base_type::f: return sizeof(f32) * size;
|
||||
case Vertex_base_type::sf:
|
||||
case vertex_base_type::f: return sizeof(f32) * size;
|
||||
case vertex_base_type::sf:
|
||||
switch (size)
|
||||
{
|
||||
case 1:
|
||||
@@ -147,7 +149,7 @@ namespace rsx
|
||||
return sizeof(f16) * 4;
|
||||
}
|
||||
throw new EXCEPTION("Wrong vector size");
|
||||
case Vertex_base_type::ub:
|
||||
case vertex_base_type::ub:
|
||||
switch (size)
|
||||
{
|
||||
case 1:
|
||||
@@ -158,16 +160,16 @@ namespace rsx
|
||||
return sizeof(u8) * 4;
|
||||
}
|
||||
throw new EXCEPTION("Wrong vector size");
|
||||
case Vertex_base_type::s32k: return sizeof(u32) * size;
|
||||
case Vertex_base_type::cmp: return sizeof(u16) * 4;
|
||||
case Vertex_base_type::ub256: return sizeof(u8) * 4;
|
||||
case vertex_base_type::s32k: return sizeof(u32) * size;
|
||||
case vertex_base_type::cmp: return sizeof(u16) * 4;
|
||||
case vertex_base_type::ub256: return sizeof(u8) * 4;
|
||||
|
||||
default:
|
||||
throw new EXCEPTION("RSXVertexData::GetTypeSize: Bad vertex data type (%d)!", type);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void tiled_region::write(const void *src, u32 width, u32 height, u32 pitch)
|
||||
{
|
||||
if (!tile)
|
||||
@@ -270,50 +272,35 @@ namespace rsx
|
||||
}
|
||||
}
|
||||
|
||||
thread::thread()
|
||||
{
|
||||
g_access_violation_handler = [this](u32 address, bool is_writing)
|
||||
{
|
||||
return on_access_violation(address, is_writing);
|
||||
};
|
||||
m_rtts_dirty = true;
|
||||
memset(m_textures_dirty, -1, sizeof(m_textures_dirty));
|
||||
}
|
||||
|
||||
thread::~thread()
|
||||
{
|
||||
g_access_violation_handler = nullptr;
|
||||
}
|
||||
|
||||
void thread::capture_frame(const std::string &name)
|
||||
{
|
||||
frame_capture_data::draw_state draw_state = {};
|
||||
|
||||
int clip_w = rsx::method_registers[NV4097_SET_SURFACE_CLIP_HORIZONTAL] >> 16;
|
||||
int clip_h = rsx::method_registers[NV4097_SET_SURFACE_CLIP_VERTICAL] >> 16;
|
||||
size_t pitch = clip_w * 4;
|
||||
std::vector<size_t> color_index_to_record;
|
||||
switch (method_registers[NV4097_SET_SURFACE_COLOR_TARGET])
|
||||
{
|
||||
case CELL_GCM_SURFACE_TARGET_0:
|
||||
color_index_to_record = { 0 };
|
||||
break;
|
||||
case CELL_GCM_SURFACE_TARGET_1:
|
||||
color_index_to_record = { 1 };
|
||||
break;
|
||||
case CELL_GCM_SURFACE_TARGET_MRT1:
|
||||
color_index_to_record = { 0, 1 };
|
||||
break;
|
||||
case CELL_GCM_SURFACE_TARGET_MRT2:
|
||||
color_index_to_record = { 0, 1, 2 };
|
||||
break;
|
||||
case CELL_GCM_SURFACE_TARGET_MRT3:
|
||||
color_index_to_record = { 0, 1, 2, 3 };
|
||||
break;
|
||||
}
|
||||
for (size_t i : color_index_to_record)
|
||||
{
|
||||
draw_state.color_buffer[i].width = clip_w;
|
||||
draw_state.color_buffer[i].height = clip_h;
|
||||
draw_state.color_buffer[i].data.resize(pitch * clip_h);
|
||||
copy_render_targets_to_memory(draw_state.color_buffer[i].data.data(), i);
|
||||
}
|
||||
if (get_address(method_registers[NV4097_SET_SURFACE_ZETA_OFFSET], method_registers[NV4097_SET_CONTEXT_DMA_ZETA]))
|
||||
{
|
||||
draw_state.depth.width = clip_w;
|
||||
draw_state.depth.height = clip_h;
|
||||
draw_state.depth.data.resize(clip_w * clip_h * 4);
|
||||
copy_depth_buffer_to_memory(draw_state.depth.data.data());
|
||||
draw_state.stencil.width = clip_w;
|
||||
draw_state.stencil.height = clip_h;
|
||||
draw_state.stencil.data.resize(clip_w * clip_h * 4);
|
||||
copy_stencil_buffer_to_memory(draw_state.stencil.data.data());
|
||||
}
|
||||
rsx::surface_info surface = {};
|
||||
surface.unpack(rsx::method_registers[NV4097_SET_SURFACE_FORMAT]);
|
||||
draw_state.width = clip_w;
|
||||
draw_state.height = clip_h;
|
||||
draw_state.color_format = surface.color_format;
|
||||
draw_state.color_buffer = std::move(copy_render_targets_to_memory());
|
||||
draw_state.depth_format = surface.depth_format;
|
||||
draw_state.depth_stencil = std::move(copy_depth_stencil_buffer_to_memory());
|
||||
draw_state.programs = get_programs();
|
||||
draw_state.name = name;
|
||||
frame_debug.draw_calls.push_back(draw_state);
|
||||
@@ -331,7 +318,10 @@ namespace rsx
|
||||
|
||||
if (capture_current_frame)
|
||||
{
|
||||
for (const auto &first_count : first_count_commands)
|
||||
vertex_draw_count += first_count.second;
|
||||
capture_frame("Draw " + std::to_string(vertex_draw_count));
|
||||
vertex_draw_count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -381,7 +371,7 @@ namespace rsx
|
||||
|
||||
if (put == get || !Emu.IsRunning())
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
|
||||
do_internal_task();
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -510,7 +500,7 @@ namespace rsx
|
||||
|
||||
u32 element_size = rsx::get_vertex_type_size_on_host(info.type, info.size);
|
||||
|
||||
if (info.type == Vertex_base_type::ub && info.size == 4)
|
||||
if (info.type == vertex_base_type::ub && info.size == 4)
|
||||
{
|
||||
dst[0] = src[3];
|
||||
dst[1] = src[2];
|
||||
@@ -534,6 +524,184 @@ namespace rsx
|
||||
return get_system_time() * 1000;
|
||||
}
|
||||
|
||||
void thread::do_internal_task()
|
||||
{
|
||||
if (m_internal_tasks.empty())
|
||||
{
|
||||
std::this_thread::sleep_for(1ms);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::lock_guard<std::mutex> lock{ m_mtx_task };
|
||||
|
||||
internal_task_entry &front = m_internal_tasks.front();
|
||||
|
||||
if (front.callback())
|
||||
{
|
||||
front.promise.set_value();
|
||||
m_internal_tasks.pop_front();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::future<void> thread::add_internal_task(std::function<bool()> callback)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock{ m_mtx_task };
|
||||
m_internal_tasks.emplace_back(callback);
|
||||
|
||||
return m_internal_tasks.back().promise.get_future();
|
||||
}
|
||||
|
||||
void thread::invoke(std::function<bool()> callback)
|
||||
{
|
||||
if (get_thread_ctrl() == thread_ctrl::get_current())
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (callback())
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
add_internal_task(callback).wait();
|
||||
}
|
||||
}
|
||||
|
||||
std::array<u32, 4> thread::get_color_surface_addresses() const
|
||||
{
|
||||
u32 offset_color[] =
|
||||
{
|
||||
rsx::method_registers[NV4097_SET_SURFACE_COLOR_AOFFSET],
|
||||
rsx::method_registers[NV4097_SET_SURFACE_COLOR_BOFFSET],
|
||||
rsx::method_registers[NV4097_SET_SURFACE_COLOR_COFFSET],
|
||||
rsx::method_registers[NV4097_SET_SURFACE_COLOR_DOFFSET]
|
||||
};
|
||||
u32 context_dma_color[] =
|
||||
{
|
||||
rsx::method_registers[NV4097_SET_CONTEXT_DMA_COLOR_A],
|
||||
rsx::method_registers[NV4097_SET_CONTEXT_DMA_COLOR_B],
|
||||
rsx::method_registers[NV4097_SET_CONTEXT_DMA_COLOR_C],
|
||||
rsx::method_registers[NV4097_SET_CONTEXT_DMA_COLOR_D]
|
||||
};
|
||||
return
|
||||
{
|
||||
rsx::get_address(offset_color[0], context_dma_color[0]),
|
||||
rsx::get_address(offset_color[1], context_dma_color[1]),
|
||||
rsx::get_address(offset_color[2], context_dma_color[2]),
|
||||
rsx::get_address(offset_color[3], context_dma_color[3]),
|
||||
};
|
||||
}
|
||||
|
||||
u32 thread::get_zeta_surface_address() const
|
||||
{
|
||||
u32 m_context_dma_z = rsx::method_registers[NV4097_SET_CONTEXT_DMA_ZETA];
|
||||
u32 offset_zeta = rsx::method_registers[NV4097_SET_SURFACE_ZETA_OFFSET];
|
||||
return rsx::get_address(offset_zeta, m_context_dma_z);
|
||||
}
|
||||
|
||||
RSXVertexProgram thread::get_current_vertex_program() const
|
||||
{
|
||||
RSXVertexProgram result = {};
|
||||
u32 transform_program_start = rsx::method_registers[NV4097_SET_TRANSFORM_PROGRAM_START];
|
||||
result.data.reserve((512 - transform_program_start) * 4);
|
||||
|
||||
for (int i = transform_program_start; i < 512; ++i)
|
||||
{
|
||||
result.data.resize((i - transform_program_start) * 4 + 4);
|
||||
memcpy(result.data.data() + (i - transform_program_start) * 4, transform_program + i * 4, 4 * sizeof(u32));
|
||||
|
||||
D3 d3;
|
||||
d3.HEX = transform_program[i * 4 + 3];
|
||||
|
||||
if (d3.end)
|
||||
break;
|
||||
}
|
||||
result.output_mask = rsx::method_registers[NV4097_SET_VERTEX_ATTRIB_OUTPUT_MASK];
|
||||
|
||||
u32 input_mask = rsx::method_registers[NV4097_SET_VERTEX_ATTRIB_INPUT_MASK];
|
||||
u32 modulo_mask = rsx::method_registers[NV4097_SET_FREQUENCY_DIVIDER_OPERATION];
|
||||
result.rsx_vertex_inputs.clear();
|
||||
for (u8 index = 0; index < rsx::limits::vertex_count; ++index)
|
||||
{
|
||||
bool enabled = !!(input_mask & (1 << index));
|
||||
if (!enabled)
|
||||
continue;
|
||||
|
||||
if (vertex_arrays_info[index].size > 0)
|
||||
{
|
||||
result.rsx_vertex_inputs.push_back(
|
||||
{
|
||||
index,
|
||||
vertex_arrays_info[index].size,
|
||||
vertex_arrays_info[index].frequency,
|
||||
!!((modulo_mask >> index) & 0x1),
|
||||
true
|
||||
}
|
||||
);
|
||||
}
|
||||
else if (register_vertex_info[index].size > 0)
|
||||
{
|
||||
result.rsx_vertex_inputs.push_back(
|
||||
{
|
||||
index,
|
||||
register_vertex_info[index].size,
|
||||
register_vertex_info[index].frequency,
|
||||
!!((modulo_mask >> index) & 0x1),
|
||||
false
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
RSXFragmentProgram thread::get_current_fragment_program() const
|
||||
{
|
||||
RSXFragmentProgram result = {};
|
||||
u32 shader_program = rsx::method_registers[NV4097_SET_SHADER_PROGRAM];
|
||||
result.offset = shader_program & ~0x3;
|
||||
result.addr = vm::base(rsx::get_address(result.offset, (shader_program & 0x3) - 1));
|
||||
result.ctrl = rsx::method_registers[NV4097_SET_SHADER_CONTROL];
|
||||
result.unnormalized_coords = 0;
|
||||
result.front_back_color_enabled = !rsx::method_registers[NV4097_SET_TWO_SIDE_LIGHT_EN];
|
||||
result.back_color_diffuse_output = !!(rsx::method_registers[NV4097_SET_VERTEX_ATTRIB_OUTPUT_MASK] & CELL_GCM_ATTRIB_OUTPUT_MASK_BACKDIFFUSE);
|
||||
result.back_color_specular_output = !!(rsx::method_registers[NV4097_SET_VERTEX_ATTRIB_OUTPUT_MASK] & CELL_GCM_ATTRIB_OUTPUT_MASK_BACKSPECULAR);
|
||||
result.alpha_func = to_comparaison_function(rsx::method_registers[NV4097_SET_ALPHA_FUNC]);
|
||||
u32 shader_window = rsx::method_registers[NV4097_SET_SHADER_WINDOW];
|
||||
result.origin_mode = rsx::to_window_origin((shader_window >> 12) & 0xF);
|
||||
result.pixel_center_mode = rsx::to_window_pixel_center((shader_window >> 16) & 0xF);
|
||||
result.height = shader_window & 0xFFF;
|
||||
|
||||
std::array<texture_dimension, 16> texture_dimensions;
|
||||
for (u32 i = 0; i < rsx::limits::textures_count; ++i)
|
||||
{
|
||||
if (!textures[i].enabled())
|
||||
texture_dimensions[i] = texture_dimension::texture_dimension_2d;
|
||||
else if (textures[i].dimension() == 1)
|
||||
texture_dimensions[i] = texture_dimension::texture_dimension_1d;
|
||||
else if (textures[i].dimension() == 2)
|
||||
{
|
||||
if (textures[i].cubemap())
|
||||
texture_dimensions[i] = texture_dimension::texture_dimension_cubemap;
|
||||
else
|
||||
texture_dimensions[i] = texture_dimension::texture_dimension_2d;
|
||||
}
|
||||
else if (textures[i].dimension() == 3)
|
||||
texture_dimensions[i] = texture_dimension::texture_dimension_3d;
|
||||
else
|
||||
throw EXCEPTION("Unable to determine texture dimension");
|
||||
if (textures[i].enabled() && (textures[i].format() & CELL_GCM_TEXTURE_UN))
|
||||
result.unnormalized_coords |= (1 << i);
|
||||
}
|
||||
result.set_texture_dimension(texture_dimensions);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void thread::reset()
|
||||
{
|
||||
//setup method registers
|
||||
@@ -598,6 +766,8 @@ namespace rsx
|
||||
method_registers[NV4097_SET_ZSTENCIL_CLEAR_VALUE] = 0xffffffff;
|
||||
|
||||
method_registers[NV4097_SET_CONTEXT_DMA_REPORT] = CELL_GCM_CONTEXT_DMA_TO_MEMORY_GET_REPORT;
|
||||
rsx::method_registers[NV4097_SET_TWO_SIDE_LIGHT_EN] = true;
|
||||
rsx::method_registers[NV4097_SET_ALPHA_FUNC] = CELL_GCM_ALWAYS;
|
||||
|
||||
// Reset vertex attrib array
|
||||
for (int i = 0; i < limits::vertex_count; i++)
|
||||
|
||||
+61
-35
@@ -15,19 +15,15 @@ extern u64 get_system_time();
|
||||
|
||||
struct frame_capture_data
|
||||
{
|
||||
struct buffer
|
||||
{
|
||||
std::vector<u8> data;
|
||||
size_t width = 0, height = 0;
|
||||
};
|
||||
|
||||
struct draw_state
|
||||
{
|
||||
std::string name;
|
||||
std::pair<std::string, std::string> programs;
|
||||
buffer color_buffer[4];
|
||||
buffer depth;
|
||||
buffer stencil;
|
||||
size_t width = 0, height = 0;
|
||||
rsx::surface_color_format color_format;
|
||||
std::array<std::vector<gsl::byte>, 4> color_buffer;
|
||||
rsx::surface_depth_format depth_format;
|
||||
std::array<std::vector<gsl::byte>, 2> depth_stencil;
|
||||
};
|
||||
std::vector<std::pair<u32, u32> > command_queue;
|
||||
std::vector<draw_state> draw_calls;
|
||||
@@ -148,7 +144,7 @@ namespace rsx
|
||||
static std::string path_to_root();
|
||||
};
|
||||
|
||||
u32 get_vertex_type_size_on_host(Vertex_base_type type, u32 size);
|
||||
u32 get_vertex_type_size_on_host(vertex_base_type type, u32 size);
|
||||
|
||||
u32 get_address(u32 offset, u32 location);
|
||||
|
||||
@@ -167,9 +163,9 @@ namespace rsx
|
||||
{
|
||||
u8 log2height;
|
||||
u8 log2width;
|
||||
u8 antialias;
|
||||
u8 depth_format;
|
||||
u8 color_format;
|
||||
surface_antialiasing antialias;
|
||||
surface_depth_format depth_format;
|
||||
surface_color_format color_format;
|
||||
|
||||
u32 width;
|
||||
u32 height;
|
||||
@@ -181,9 +177,9 @@ namespace rsx
|
||||
|
||||
log2height = surface_format >> 24;
|
||||
log2width = (surface_format >> 16) & 0xff;
|
||||
antialias = (surface_format >> 12) & 0xf;
|
||||
depth_format = (surface_format >> 5) & 0x7;
|
||||
color_format = surface_format & 0x1f;
|
||||
antialias = to_surface_antialiasing((surface_format >> 12) & 0xf);
|
||||
depth_format = to_surface_depth_format((surface_format >> 5) & 0x7);
|
||||
color_format = to_surface_color_format(surface_format & 0x1f);
|
||||
|
||||
width = 1 << (u32(log2width) + 1);
|
||||
height = 1 << (u32(log2width) + 1);
|
||||
@@ -195,7 +191,7 @@ namespace rsx
|
||||
u16 frequency = 0;
|
||||
u8 stride = 0;
|
||||
u8 size = 0;
|
||||
Vertex_base_type type = Vertex_base_type::f;
|
||||
vertex_base_type type = vertex_base_type::f;
|
||||
|
||||
void unpack_array(u32 data_array_format)
|
||||
{
|
||||
@@ -206,6 +202,13 @@ namespace rsx
|
||||
}
|
||||
};
|
||||
|
||||
enum class draw_command
|
||||
{
|
||||
array,
|
||||
inlined_array,
|
||||
indexed,
|
||||
};
|
||||
|
||||
class thread : public named_thread_t
|
||||
{
|
||||
protected:
|
||||
@@ -260,6 +263,7 @@ namespace rsx
|
||||
|
||||
bool capture_current_frame = false;
|
||||
void capture_frame(const std::string &name);
|
||||
|
||||
public:
|
||||
u32 ioAddress, ioSize;
|
||||
int flip_status;
|
||||
@@ -275,21 +279,22 @@ namespace rsx
|
||||
u32 ctxt_addr;
|
||||
u32 report_main_addr;
|
||||
u32 label_addr;
|
||||
enum class Draw_command
|
||||
{
|
||||
draw_command_array,
|
||||
draw_command_inlined_array,
|
||||
draw_command_indexed,
|
||||
} draw_command;
|
||||
Primitive_type draw_mode;
|
||||
rsx::draw_command draw_command;
|
||||
primitive_type draw_mode;
|
||||
|
||||
u32 local_mem_addr, main_mem_addr;
|
||||
bool strict_ordering[0x1000];
|
||||
|
||||
|
||||
bool draw_inline_vertex_array;
|
||||
std::vector<u32> inline_vertex_array;
|
||||
|
||||
bool m_rtts_dirty;
|
||||
bool m_textures_dirty[16];
|
||||
protected:
|
||||
std::array<u32, 4> get_color_surface_addresses() const;
|
||||
u32 get_zeta_surface_address() const;
|
||||
RSXVertexProgram get_current_vertex_program() const;
|
||||
RSXFragmentProgram get_current_fragment_program() const;
|
||||
public:
|
||||
u32 draw_array_count;
|
||||
u32 draw_array_first;
|
||||
@@ -307,7 +312,8 @@ namespace rsx
|
||||
std::set<u32> m_used_gcm_commands;
|
||||
|
||||
protected:
|
||||
virtual ~thread() {}
|
||||
thread();
|
||||
virtual ~thread();
|
||||
|
||||
virtual void on_task() override;
|
||||
|
||||
@@ -322,6 +328,27 @@ namespace rsx
|
||||
virtual bool do_method(u32 cmd, u32 value) { return false; }
|
||||
virtual void flip(int buffer) = 0;
|
||||
virtual u64 timestamp() const;
|
||||
virtual bool on_access_violation(u32 address, bool is_writing) { return false; }
|
||||
|
||||
private:
|
||||
std::mutex m_mtx_task;
|
||||
|
||||
struct internal_task_entry
|
||||
{
|
||||
std::function<bool()> callback;
|
||||
std::promise<void> promise;
|
||||
|
||||
internal_task_entry(std::function<bool()> callback) : callback(callback)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
std::deque<internal_task_entry> m_internal_tasks;
|
||||
void do_internal_task();
|
||||
|
||||
public:
|
||||
std::future<void> add_internal_task(std::function<bool()> callback);
|
||||
void invoke(std::function<bool()> callback);
|
||||
|
||||
/**
|
||||
* Fill buffer with 4x4 scale offset matrix.
|
||||
@@ -347,21 +374,20 @@ namespace rsx
|
||||
* Copy rtt values to buffer.
|
||||
* TODO: It's more efficient to combine multiple call of this function into one.
|
||||
*/
|
||||
virtual void copy_render_targets_to_memory(void *buffer, u8 rtt) {};
|
||||
virtual std::array<std::vector<gsl::byte>, 4> copy_render_targets_to_memory() {
|
||||
return std::array<std::vector<gsl::byte>, 4>();
|
||||
};
|
||||
|
||||
/**
|
||||
* Copy depth content to buffer.
|
||||
* Copy depth and stencil content to buffers.
|
||||
* TODO: It's more efficient to combine multiple call of this function into one.
|
||||
*/
|
||||
virtual void copy_depth_buffer_to_memory(void *buffer) {};
|
||||
|
||||
/**
|
||||
* Copy stencil content to buffer.
|
||||
* TODO: It's more efficient to combine multiple call of this function into one.
|
||||
*/
|
||||
virtual void copy_stencil_buffer_to_memory(void *buffer) {};
|
||||
virtual std::array<std::vector<gsl::byte>, 2> copy_depth_stencil_buffer_to_memory() {
|
||||
return std::array<std::vector<gsl::byte>, 2>();
|
||||
};
|
||||
|
||||
virtual std::pair<std::string, std::string> get_programs() const { return std::make_pair("", ""); };
|
||||
|
||||
public:
|
||||
void reset();
|
||||
void init(const u32 ioAddress, const u32 ioSize, const u32 ctrlAddress, const u32 localAddress);
|
||||
|
||||
@@ -190,7 +190,23 @@ static const std::string rsx_vp_vec_op_names[] =
|
||||
"SEQ", "SFL", "SGT", "SLE", "SNE", "STR", "SSG", "NULL", "NULL", "TXL"
|
||||
};
|
||||
|
||||
struct rsx_vertex_input
|
||||
{
|
||||
u8 location; // between 0 and 15
|
||||
u8 size; // between 1 and 4
|
||||
u16 frequency;
|
||||
bool is_modulo; // either modulo frequency or divide frequency
|
||||
bool is_array; // false if "reg value"
|
||||
|
||||
bool operator==(const rsx_vertex_input other) const
|
||||
{
|
||||
return location == other.location && size == other.size && frequency == other.frequency && is_modulo == other.is_modulo && is_array == other.is_array;
|
||||
}
|
||||
};
|
||||
|
||||
struct RSXVertexProgram
|
||||
{
|
||||
std::vector<u32> data;
|
||||
std::vector<rsx_vertex_input> rsx_vertex_inputs;
|
||||
u32 output_mask;
|
||||
};
|
||||
|
||||
@@ -14,10 +14,10 @@ namespace rsx
|
||||
rsx_method_t methods[0x10000 >> 2]{};
|
||||
|
||||
template<typename Type> struct vertex_data_type_from_element_type;
|
||||
template<> struct vertex_data_type_from_element_type<float> { static const Vertex_base_type type = Vertex_base_type::f; };
|
||||
template<> struct vertex_data_type_from_element_type<f16> { static const Vertex_base_type type = Vertex_base_type::sf; };
|
||||
template<> struct vertex_data_type_from_element_type<u8> { static const Vertex_base_type type = Vertex_base_type::ub; };
|
||||
template<> struct vertex_data_type_from_element_type<u16> { static const Vertex_base_type type = Vertex_base_type::s1; };
|
||||
template<> struct vertex_data_type_from_element_type<float> { static const vertex_base_type type = vertex_base_type::f; };
|
||||
template<> struct vertex_data_type_from_element_type<f16> { static const vertex_base_type type = vertex_base_type::sf; };
|
||||
template<> struct vertex_data_type_from_element_type<u8> { static const vertex_base_type type = vertex_base_type::ub; };
|
||||
template<> struct vertex_data_type_from_element_type<u16> { static const vertex_base_type type = vertex_base_type::s1; };
|
||||
|
||||
namespace nv406e
|
||||
{
|
||||
@@ -160,7 +160,7 @@ namespace rsx
|
||||
|
||||
force_inline void draw_arrays(thread* rsx, u32 arg)
|
||||
{
|
||||
rsx->draw_command = thread::Draw_command::draw_command_array;
|
||||
rsx->draw_command = rsx::draw_command::array;
|
||||
u32 first = arg & 0xffffff;
|
||||
u32 count = (arg >> 24) + 1;
|
||||
|
||||
@@ -169,7 +169,7 @@ namespace rsx
|
||||
|
||||
force_inline void draw_index_array(thread* rsx, u32 arg)
|
||||
{
|
||||
rsx->draw_command = thread::Draw_command::draw_command_indexed;
|
||||
rsx->draw_command = rsx::draw_command::indexed;
|
||||
u32 first = arg & 0xffffff;
|
||||
u32 count = (arg >> 24) + 1;
|
||||
|
||||
@@ -178,7 +178,7 @@ namespace rsx
|
||||
|
||||
force_inline void draw_inline_array(thread* rsx, u32 arg)
|
||||
{
|
||||
rsx->draw_command = thread::Draw_command::draw_command_inlined_array;
|
||||
rsx->draw_command = rsx::draw_command::inlined_array;
|
||||
rsx->draw_inline_vertex_array = true;
|
||||
rsx->inline_vertex_array.push_back(arg);
|
||||
}
|
||||
@@ -282,6 +282,20 @@ namespace rsx
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
force_inline void set_surface_dirty_bit(thread* rsx, u32)
|
||||
{
|
||||
rsx->m_rtts_dirty = true;
|
||||
}
|
||||
|
||||
template<u32 index>
|
||||
struct set_texture_dirty_bit
|
||||
{
|
||||
force_inline static void impl(thread* rsx, u32 arg)
|
||||
{
|
||||
rsx->m_textures_dirty[index] = true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace nv308a
|
||||
@@ -656,9 +670,9 @@ namespace rsx
|
||||
double limit;
|
||||
switch (rpcs3::state.config.rsx.frame_limit.value())
|
||||
{
|
||||
case rsx_frame_limit::_30: limit = 30.; break;
|
||||
case rsx_frame_limit::_50: limit = 50.; break;
|
||||
case rsx_frame_limit::_59_94: limit = 59.94; break;
|
||||
case rsx_frame_limit::_30: limit = 30.; break;
|
||||
case rsx_frame_limit::_60: limit = 60.; break;
|
||||
case rsx_frame_limit::Auto: limit = rsx->fps_limit; break; //TODO
|
||||
|
||||
@@ -786,6 +800,16 @@ namespace rsx
|
||||
bind<NV406E_SEMAPHORE_ACQUIRE, nv406e::semaphore_acquire>();
|
||||
bind<NV406E_SEMAPHORE_RELEASE, nv406e::semaphore_release>();
|
||||
|
||||
/*
|
||||
|
||||
// Store previous fbo addresses to detect RTT config changes.
|
||||
std::array<u32, 4> m_previous_color_address = {};
|
||||
u32 m_previous_address_z = 0;
|
||||
u32 m_previous_target = 0;
|
||||
u32 m_previous_clip_horizontal = 0;
|
||||
u32 m_previous_clip_vertical = 0;
|
||||
*/
|
||||
|
||||
// NV4097
|
||||
bind<NV4097_TEXTURE_READ_SEMAPHORE_RELEASE, nv4097::texture_read_semaphore_release>();
|
||||
bind<NV4097_BACK_END_WRITE_SEMAPHORE_RELEASE, nv4097::back_end_write_semaphore_release>();
|
||||
@@ -806,6 +830,29 @@ namespace rsx
|
||||
bind_range<NV4097_SET_TRANSFORM_PROGRAM + 3, 4, 128, nv4097::set_transform_program>();
|
||||
bind_cpu_only<NV4097_GET_REPORT, nv4097::get_report>();
|
||||
bind_cpu_only<NV4097_CLEAR_REPORT_VALUE, nv4097::clear_report_value>();
|
||||
bind<NV4097_SET_SURFACE_CLIP_HORIZONTAL, nv4097::set_surface_dirty_bit>();
|
||||
bind<NV4097_SET_SURFACE_CLIP_VERTICAL, nv4097::set_surface_dirty_bit>();
|
||||
bind<NV4097_SET_SURFACE_COLOR_AOFFSET, nv4097::set_surface_dirty_bit>();
|
||||
bind<NV4097_SET_SURFACE_COLOR_BOFFSET, nv4097::set_surface_dirty_bit>();
|
||||
bind<NV4097_SET_SURFACE_COLOR_COFFSET, nv4097::set_surface_dirty_bit>();
|
||||
bind<NV4097_SET_SURFACE_COLOR_DOFFSET, nv4097::set_surface_dirty_bit>();
|
||||
bind<NV4097_SET_SURFACE_ZETA_OFFSET, nv4097::set_surface_dirty_bit>();
|
||||
bind<NV4097_SET_CONTEXT_DMA_COLOR_A, nv4097::set_surface_dirty_bit>();
|
||||
bind<NV4097_SET_CONTEXT_DMA_COLOR_B, nv4097::set_surface_dirty_bit>();
|
||||
bind<NV4097_SET_CONTEXT_DMA_COLOR_C, nv4097::set_surface_dirty_bit>();
|
||||
bind<NV4097_SET_CONTEXT_DMA_COLOR_D, nv4097::set_surface_dirty_bit>();
|
||||
bind<NV4097_SET_CONTEXT_DMA_ZETA, nv4097::set_surface_dirty_bit>();
|
||||
bind<NV4097_SET_SURFACE_FORMAT, nv4097::set_surface_dirty_bit>();
|
||||
bind_range<NV4097_SET_TEXTURE_OFFSET, 8, 16, nv4097::set_texture_dirty_bit>();
|
||||
bind_range<NV4097_SET_TEXTURE_FORMAT, 8, 16, nv4097::set_texture_dirty_bit>();
|
||||
bind_range<NV4097_SET_TEXTURE_ADDRESS, 8, 16, nv4097::set_texture_dirty_bit>();
|
||||
bind_range<NV4097_SET_TEXTURE_CONTROL0, 8, 16, nv4097::set_texture_dirty_bit>();
|
||||
bind_range<NV4097_SET_TEXTURE_CONTROL1, 8, 16, nv4097::set_texture_dirty_bit>();
|
||||
bind_range<NV4097_SET_TEXTURE_CONTROL2, 8, 16, nv4097::set_texture_dirty_bit>();
|
||||
bind_range<NV4097_SET_TEXTURE_CONTROL3, 1, 16, nv4097::set_texture_dirty_bit>();
|
||||
bind_range<NV4097_SET_TEXTURE_FILTER, 8, 16, nv4097::set_texture_dirty_bit>();
|
||||
bind_range<NV4097_SET_TEXTURE_IMAGE_RECT, 8, 16, nv4097::set_texture_dirty_bit>();
|
||||
bind_range<NV4097_SET_TEXTURE_BORDER_COLOR, 8, 16, nv4097::set_texture_dirty_bit>();
|
||||
|
||||
//NV308A
|
||||
bind_range<NV308A_COLOR, 1, 256, nv308a::color>();
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace rsx
|
||||
u32 y_mask = 0xAAAAAAAA;
|
||||
|
||||
// We have to limit the masks to the lower of the two dimensions to allow for non-square textures
|
||||
u16 limit_mask = (log2width < log2height) ? log2width : log2height;
|
||||
u32 limit_mask = (log2width < log2height) ? log2width : log2height;
|
||||
// double the limit mask to account for bits in both x and y
|
||||
limit_mask = 1 << (limit_mask << 1);
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ struct content_permission_t final
|
||||
|
||||
s32 cellHddGameCheck(PPUThread& ppu, u32 version, vm::cptr<char> dirName, u32 errDialog, vm::ptr<CellHddGameStatCallback> funcStat, u32 container)
|
||||
{
|
||||
cellGame.warning("cellHddGameCheck(version=%d, dirName=*0x%x, errDialog=%d, funcStat=*0x%x, container=%d)", version, dirName, errDialog, funcStat, container);
|
||||
cellGame.error("cellHddGameCheck(version=%d, dirName=*0x%x, errDialog=%d, funcStat=*0x%x, container=%d)", version, dirName, errDialog, funcStat, container);
|
||||
|
||||
std::string dir = dirName.get_ptr();
|
||||
|
||||
@@ -78,27 +78,19 @@ s32 cellHddGameCheck(PPUThread& ppu, u32 version, vm::cptr<char> dirName, u32 er
|
||||
else
|
||||
{
|
||||
// TODO: Is cellHddGameCheck really responsible for writing the information in get->getParam ? (If not, delete this else)
|
||||
vfsFile f("/dev_hdd0/game/" + dir + "/PARAM.SFO");
|
||||
const PSFLoader psf(f);
|
||||
if (!psf)
|
||||
{
|
||||
return CELL_HDDGAME_ERROR_BROKEN;
|
||||
}
|
||||
const auto& psf = psf::load(vfsFile("/dev_hdd0/game/" + dir + "/PARAM.SFO").VRead<char>());
|
||||
|
||||
get->getParam.parentalLevel = psf.GetInteger("PARENTAL_LEVEL");
|
||||
get->getParam.attribute = psf.GetInteger("ATTRIBUTE");
|
||||
get->getParam.resolution = psf.GetInteger("RESOLUTION");
|
||||
get->getParam.soundFormat = psf.GetInteger("SOUND_FORMAT");
|
||||
std::string title = psf.GetString("TITLE");
|
||||
strcpy_trunc(get->getParam.title, title);
|
||||
std::string app_ver = psf.GetString("APP_VER");
|
||||
strcpy_trunc(get->getParam.dataVersion, app_ver);
|
||||
strcpy_trunc(get->getParam.titleId, dir);
|
||||
get->getParam.parentalLevel = psf.at("PARENTAL_LEVEL").as_integer();
|
||||
get->getParam.attribute = psf.at("ATTRIBUTE").as_integer();
|
||||
get->getParam.resolution = psf.at("RESOLUTION").as_integer();
|
||||
get->getParam.soundFormat = psf.at("SOUND_FORMAT").as_integer();
|
||||
strcpy_trunc(get->getParam.title, psf.at("TITLE").as_string());
|
||||
strcpy_trunc(get->getParam.dataVersion, psf.at("APP_VER").as_string());
|
||||
strcpy_trunc(get->getParam.titleId, psf.at("TITLE_ID").as_string());
|
||||
|
||||
for (u32 i = 0; i < CELL_HDDGAME_SYSP_LANGUAGE_NUM; i++)
|
||||
{
|
||||
title = psf.GetString(fmt::format("TITLE_%02d", i));
|
||||
strcpy_trunc(get->getParam.titleLang[i], title);
|
||||
strcpy_trunc(get->getParam.titleLang[i], psf::get_string(psf, fmt::format("TITLE_%02d", i)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,17 +159,17 @@ s32 cellGameBootCheck(vm::ptr<u32> type, vm::ptr<u32> attributes, vm::ptr<CellGa
|
||||
size->sysSizeKB = 0;
|
||||
}
|
||||
|
||||
vfsFile f("/app_home/../PARAM.SFO");
|
||||
const PSFLoader psf(f);
|
||||
const auto& psf = psf::load(vfsFile("/app_home/../PARAM.SFO").VRead<char>());
|
||||
|
||||
if (!psf)
|
||||
if (psf.empty())
|
||||
{
|
||||
// According to testing (in debug mode) cellGameBootCheck doesn't return an error code, when PARAM.SFO doesn't exist.
|
||||
cellGame.error("cellGameBootCheck(): Cannot read PARAM.SFO.");
|
||||
return CELL_GAME_RET_OK;
|
||||
}
|
||||
|
||||
std::string category = psf.GetString("CATEGORY");
|
||||
if (category.substr(0, 2) == "DG")
|
||||
const std::string& category = psf.at("CATEGORY").as_string();
|
||||
if (category == "DG")
|
||||
{
|
||||
*type = CELL_GAME_GAMETYPE_DISC;
|
||||
*attributes = 0; // TODO
|
||||
@@ -188,9 +180,9 @@ s32 cellGameBootCheck(vm::ptr<u32> type, vm::ptr<u32> attributes, vm::ptr<CellGa
|
||||
return CELL_GAME_ERROR_BUSY;
|
||||
}
|
||||
}
|
||||
else if (category.substr(0, 2) == "HG")
|
||||
else if (category == "HG")
|
||||
{
|
||||
std::string titleId = psf.GetString("TITLE_ID");
|
||||
const std::string& titleId = psf.at("TITLE_ID").as_string();
|
||||
*type = CELL_GAME_GAMETYPE_HDD;
|
||||
*attributes = 0; // TODO
|
||||
if (dirName) strcpy_trunc(*dirName, titleId);
|
||||
@@ -200,9 +192,9 @@ s32 cellGameBootCheck(vm::ptr<u32> type, vm::ptr<u32> attributes, vm::ptr<CellGa
|
||||
return CELL_GAME_ERROR_BUSY;
|
||||
}
|
||||
}
|
||||
else if (category.substr(0, 2) == "GD")
|
||||
else if (category == "GD")
|
||||
{
|
||||
std::string titleId = psf.GetString("TITLE_ID");
|
||||
const std::string& titleId = psf.at("TITLE_ID").as_string();
|
||||
*type = CELL_GAME_GAMETYPE_DISC;
|
||||
*attributes = CELL_GAME_ATTRIBUTE_PATCH; // TODO
|
||||
if (dirName) strcpy_trunc(*dirName, titleId); // ???
|
||||
@@ -212,7 +204,7 @@ s32 cellGameBootCheck(vm::ptr<u32> type, vm::ptr<u32> attributes, vm::ptr<CellGa
|
||||
return CELL_GAME_ERROR_BUSY;
|
||||
}
|
||||
}
|
||||
else if (psf)
|
||||
else
|
||||
{
|
||||
cellGame.error("cellGameBootCheck(): Unknown CATEGORY.");
|
||||
}
|
||||
@@ -234,22 +226,15 @@ s32 cellGamePatchCheck(vm::ptr<CellGameContentSize> size, vm::ptr<void> reserved
|
||||
size->sysSizeKB = 0;
|
||||
}
|
||||
|
||||
vfsFile f("/app_home/../PARAM.SFO");
|
||||
const PSFLoader psf(f);
|
||||
if (!psf)
|
||||
{
|
||||
cellGame.error("cellGamePatchCheck(): CELL_GAME_ERROR_ACCESS_ERROR (cannot read PARAM.SFO)");
|
||||
return CELL_GAME_ERROR_ACCESS_ERROR;
|
||||
}
|
||||
const auto& psf = psf::load(vfsFile("/app_home/../PARAM.SFO").VRead<char>());
|
||||
|
||||
std::string category = psf.GetString("CATEGORY");
|
||||
if (category.substr(0, 2) != "GD")
|
||||
if (psf.empty() || psf.at("CATEGORY").as_string() != "GD")
|
||||
{
|
||||
cellGame.error("cellGamePatchCheck(): CELL_GAME_ERROR_NOTPATCH");
|
||||
return CELL_GAME_ERROR_NOTPATCH;
|
||||
}
|
||||
|
||||
if (!fxm::make<content_permission_t>("/dev_hdd0/game/" + psf.GetString("TITLE_ID"), false))
|
||||
if (!fxm::make<content_permission_t>("/dev_hdd0/game/" + psf.at("TITLE_ID").as_string(), false))
|
||||
{
|
||||
return CELL_GAME_ERROR_BUSY;
|
||||
}
|
||||
@@ -358,7 +343,7 @@ s32 cellGameContentPermit(vm::ptr<char[CELL_GAME_PATH_MAX]> contentInfoPath, vm:
|
||||
|
||||
s32 cellGameDataCheckCreate2(PPUThread& ppu, u32 version, vm::cptr<char> dirName, u32 errDialog, vm::ptr<CellGameDataStatCallback> funcStat, u32 container)
|
||||
{
|
||||
cellGame.warning("cellGameDataCheckCreate2(version=0x%x, dirName=*0x%x, errDialog=0x%x, funcStat=*0x%x, container=%d)", version, dirName, errDialog, funcStat, container);
|
||||
cellGame.error("cellGameDataCheckCreate2(version=0x%x, dirName=*0x%x, errDialog=0x%x, funcStat=*0x%x, container=%d)", version, dirName, errDialog, funcStat, container);
|
||||
|
||||
if (version != CELL_GAMEDATA_VERSION_CURRENT || errDialog > 1)
|
||||
{
|
||||
@@ -377,13 +362,7 @@ s32 cellGameDataCheckCreate2(PPUThread& ppu, u32 version, vm::cptr<char> dirName
|
||||
return CELL_GAMEDATA_RET_OK;
|
||||
}
|
||||
|
||||
vfsFile f("/app_home/../PARAM.SFO");
|
||||
const PSFLoader psf(f);
|
||||
if (!psf)
|
||||
{
|
||||
cellGame.error("cellGameDataCheckCreate2(): CELL_GAMEDATA_ERROR_BROKEN (cannot read PARAM.SFO)");
|
||||
return CELL_GAMEDATA_ERROR_BROKEN;
|
||||
}
|
||||
const auto& psf = psf::load(vfsFile("/app_home/../PARAM.SFO").VRead<char>());
|
||||
|
||||
vm::var<CellGameDataCBResult> cbResult;
|
||||
vm::var<CellGameDataStatGet> cbGet;
|
||||
@@ -406,10 +385,10 @@ s32 cellGameDataCheckCreate2(PPUThread& ppu, u32 version, vm::cptr<char> dirName
|
||||
cbGet->sysSizeKB = 0;
|
||||
|
||||
cbGet->getParam.attribute = CELL_GAMEDATA_ATTR_NORMAL;
|
||||
cbGet->getParam.parentalLevel = psf.GetInteger("PARENTAL_LEVEL");
|
||||
strcpy_trunc(cbGet->getParam.dataVersion, psf.GetString("APP_VER"));
|
||||
strcpy_trunc(cbGet->getParam.titleId, psf.GetString("TITLE_ID"));
|
||||
strcpy_trunc(cbGet->getParam.title, psf.GetString("TITLE"));
|
||||
cbGet->getParam.parentalLevel = psf.at("PARENTAL_LEVEL").as_integer();
|
||||
strcpy_trunc(cbGet->getParam.dataVersion, psf.at("APP_VER").as_string());
|
||||
strcpy_trunc(cbGet->getParam.titleId, psf.at("TITLE_ID").as_string());
|
||||
strcpy_trunc(cbGet->getParam.title, psf.at("TITLE").as_string());
|
||||
// TODO: write lang titles
|
||||
|
||||
funcStat(ppu, cbResult, cbGet, cbSet);
|
||||
@@ -505,26 +484,21 @@ s32 cellGameGetParamInt(u32 id, vm::ptr<u32> value)
|
||||
{
|
||||
cellGame.warning("cellGameGetParamInt(id=%d, value=*0x%x)", id, value);
|
||||
|
||||
// TODO: Access through cellGame***Check functions
|
||||
vfsFile f("/app_home/../PARAM.SFO");
|
||||
const PSFLoader psf(f);
|
||||
const auto& psf = psf::load(vfsFile("/app_home/../PARAM.SFO").VRead<char>());
|
||||
|
||||
if (!psf)
|
||||
{
|
||||
return CELL_GAME_ERROR_FAILURE;
|
||||
}
|
||||
std::string key;
|
||||
|
||||
switch(id)
|
||||
{
|
||||
case CELL_GAME_PARAMID_PARENTAL_LEVEL: *value = psf.GetInteger("PARENTAL_LEVEL"); break;
|
||||
case CELL_GAME_PARAMID_RESOLUTION: *value = psf.GetInteger("RESOLUTION"); break;
|
||||
case CELL_GAME_PARAMID_SOUND_FORMAT: *value = psf.GetInteger("SOUND_FORMAT"); break;
|
||||
|
||||
case CELL_GAME_PARAMID_PARENTAL_LEVEL: key = "PARENTAL_LEVEL"; break;
|
||||
case CELL_GAME_PARAMID_RESOLUTION: key = "RESOLUTION"; break;
|
||||
case CELL_GAME_PARAMID_SOUND_FORMAT: key = "SOUND_FORMAT"; break;
|
||||
default:
|
||||
cellGame.error("cellGameGetParamInt(): Unimplemented parameter (%d)", id);
|
||||
return CELL_GAME_ERROR_INVALID_ID;
|
||||
}
|
||||
|
||||
*value = psf.at(key).as_integer();
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
@@ -532,50 +506,46 @@ s32 cellGameGetParamString(u32 id, vm::ptr<char> buf, u32 bufsize)
|
||||
{
|
||||
cellGame.warning("cellGameGetParamString(id=%d, buf=*0x%x, bufsize=%d)", id, buf, bufsize);
|
||||
|
||||
// TODO: Access through cellGame***Check functions
|
||||
vfsFile f("/app_home/../PARAM.SFO");
|
||||
const PSFLoader psf(f);
|
||||
if (!psf)
|
||||
{
|
||||
return CELL_GAME_ERROR_FAILURE;
|
||||
}
|
||||
const auto& psf = psf::load(vfsFile("/app_home/../PARAM.SFO").VRead<char>());
|
||||
|
||||
std::string data;
|
||||
std::string key;
|
||||
switch(id)
|
||||
{
|
||||
case CELL_GAME_PARAMID_TITLE: data = psf.GetString("TITLE"); break; // TODO: Is this value correct?
|
||||
case CELL_GAME_PARAMID_TITLE_DEFAULT: data = psf.GetString("TITLE"); break;
|
||||
case CELL_GAME_PARAMID_TITLE_JAPANESE: data = psf.GetString("TITLE_00"); break;
|
||||
case CELL_GAME_PARAMID_TITLE_ENGLISH: data = psf.GetString("TITLE_01"); break;
|
||||
case CELL_GAME_PARAMID_TITLE_FRENCH: data = psf.GetString("TITLE_02"); break;
|
||||
case CELL_GAME_PARAMID_TITLE_SPANISH: data = psf.GetString("TITLE_03"); break;
|
||||
case CELL_GAME_PARAMID_TITLE_GERMAN: data = psf.GetString("TITLE_04"); break;
|
||||
case CELL_GAME_PARAMID_TITLE_ITALIAN: data = psf.GetString("TITLE_05"); break;
|
||||
case CELL_GAME_PARAMID_TITLE_DUTCH: data = psf.GetString("TITLE_06"); break;
|
||||
case CELL_GAME_PARAMID_TITLE_PORTUGUESE: data = psf.GetString("TITLE_07"); break;
|
||||
case CELL_GAME_PARAMID_TITLE_RUSSIAN: data = psf.GetString("TITLE_08"); break;
|
||||
case CELL_GAME_PARAMID_TITLE_KOREAN: data = psf.GetString("TITLE_09"); break;
|
||||
case CELL_GAME_PARAMID_TITLE_CHINESE_T: data = psf.GetString("TITLE_10"); break;
|
||||
case CELL_GAME_PARAMID_TITLE_CHINESE_S: data = psf.GetString("TITLE_11"); break;
|
||||
case CELL_GAME_PARAMID_TITLE_FINNISH: data = psf.GetString("TITLE_12"); break;
|
||||
case CELL_GAME_PARAMID_TITLE_SWEDISH: data = psf.GetString("TITLE_13"); break;
|
||||
case CELL_GAME_PARAMID_TITLE_DANISH: data = psf.GetString("TITLE_14"); break;
|
||||
case CELL_GAME_PARAMID_TITLE_NORWEGIAN: data = psf.GetString("TITLE_15"); break;
|
||||
case CELL_GAME_PARAMID_TITLE_POLISH: data = psf.GetString("TITLE_16"); break;
|
||||
case CELL_GAME_PARAMID_TITLE_PORTUGUESE_BRAZIL: data = psf.GetString("TITLE_17"); break;
|
||||
case CELL_GAME_PARAMID_TITLE_ENGLISH_UK: data = psf.GetString("TITLE_18"); break;
|
||||
case CELL_GAME_PARAMID_TITLE: key = "TITLE"; break; // TODO: Is this value correct?
|
||||
case CELL_GAME_PARAMID_TITLE_DEFAULT: key = "TITLE"; break;
|
||||
case CELL_GAME_PARAMID_TITLE_JAPANESE: key = "TITLE_00"; break;
|
||||
case CELL_GAME_PARAMID_TITLE_ENGLISH: key = "TITLE_01"; break;
|
||||
case CELL_GAME_PARAMID_TITLE_FRENCH: key = "TITLE_02"; break;
|
||||
case CELL_GAME_PARAMID_TITLE_SPANISH: key = "TITLE_03"; break;
|
||||
case CELL_GAME_PARAMID_TITLE_GERMAN: key = "TITLE_04"; break;
|
||||
case CELL_GAME_PARAMID_TITLE_ITALIAN: key = "TITLE_05"; break;
|
||||
case CELL_GAME_PARAMID_TITLE_DUTCH: key = "TITLE_06"; break;
|
||||
case CELL_GAME_PARAMID_TITLE_PORTUGUESE: key = "TITLE_07"; break;
|
||||
case CELL_GAME_PARAMID_TITLE_RUSSIAN: key = "TITLE_08"; break;
|
||||
case CELL_GAME_PARAMID_TITLE_KOREAN: key = "TITLE_09"; break;
|
||||
case CELL_GAME_PARAMID_TITLE_CHINESE_T: key = "TITLE_10"; break;
|
||||
case CELL_GAME_PARAMID_TITLE_CHINESE_S: key = "TITLE_11"; break;
|
||||
case CELL_GAME_PARAMID_TITLE_FINNISH: key = "TITLE_12"; break;
|
||||
case CELL_GAME_PARAMID_TITLE_SWEDISH: key = "TITLE_13"; break;
|
||||
case CELL_GAME_PARAMID_TITLE_DANISH: key = "TITLE_14"; break;
|
||||
case CELL_GAME_PARAMID_TITLE_NORWEGIAN: key = "TITLE_15"; break;
|
||||
case CELL_GAME_PARAMID_TITLE_POLISH: key = "TITLE_16"; break;
|
||||
case CELL_GAME_PARAMID_TITLE_PORTUGUESE_BRAZIL: key = "TITLE_17"; break;
|
||||
case CELL_GAME_PARAMID_TITLE_ENGLISH_UK: key = "TITLE_18"; break;
|
||||
|
||||
case CELL_GAME_PARAMID_TITLE_ID: data = psf.GetString("TITLE_ID"); break;
|
||||
case CELL_GAME_PARAMID_VERSION: data = psf.GetString("PS3_SYSTEM_VER"); break;
|
||||
case CELL_GAME_PARAMID_APP_VER: data = psf.GetString("APP_VER"); break;
|
||||
case CELL_GAME_PARAMID_TITLE_ID: key = "TITLE_ID"; break;
|
||||
case CELL_GAME_PARAMID_VERSION: key = "PS3_SYSTEM_VER"; break;
|
||||
case CELL_GAME_PARAMID_APP_VER: key = "APP_VER"; break;
|
||||
|
||||
default:
|
||||
cellGame.error("cellGameGetParamString(): Unimplemented parameter (%d)", id);
|
||||
return CELL_GAME_ERROR_INVALID_ID;
|
||||
}
|
||||
|
||||
if (data.size() >= bufsize) data.resize(bufsize - 1);
|
||||
memcpy(buf.get_ptr(), data.c_str(), data.size() + 1);
|
||||
const std::string& value = psf.at(key).as_string().substr(0, bufsize - 1);
|
||||
|
||||
std::copy_n(value.c_str(), value.size() + 1, buf.get_ptr());
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,13 @@ enum CellPngTxtType : s32
|
||||
CELL_PNG_ITXT = 2,
|
||||
};
|
||||
|
||||
enum CellPngUnknownLocation : s32
|
||||
{
|
||||
CELL_PNG_BEFORE_PLTE = 1,
|
||||
CELL_PNG_BEFORE_IDAT = 2,
|
||||
CELL_PNG_AFTER_IDAT = 8,
|
||||
};
|
||||
|
||||
struct CellPngPLTEentry
|
||||
{
|
||||
u8 red;
|
||||
@@ -33,13 +40,6 @@ struct CellPngSPLTentry
|
||||
be_t<u32> paletteEntriesNumber;
|
||||
};
|
||||
|
||||
enum CellPngUnknownLocation : s32
|
||||
{
|
||||
CELL_PNG_BEFORE_PLTE = 1,
|
||||
CELL_PNG_BEFORE_IDAT = 2,
|
||||
CELL_PNG_AFTER_IDAT = 8,
|
||||
};
|
||||
|
||||
struct CellPngTextInfo
|
||||
{
|
||||
be_t<s32> txtType; // CellPngTxtType
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -83,9 +83,20 @@ enum CellPngDecDecodeStatus : s32
|
||||
CELL_PNGDEC_DEC_STATUS_STOP = 1,
|
||||
};
|
||||
|
||||
enum CellPngDecBufferMode : s32
|
||||
{
|
||||
CELL_PNGDEC_LINE_MODE = 1,
|
||||
};
|
||||
|
||||
enum CellPngDecSpuMode : s32
|
||||
{
|
||||
CELL_PNGDEC_RECEIVE_EVENT = 0,
|
||||
CELL_PNGDEC_TRYRECEIVE_EVENT = 1,
|
||||
};
|
||||
|
||||
// Callbacks for memory management
|
||||
using CellPngDecCbControlMalloc = vm::ptr<void>(u32 size, vm::ptr<void> cbCtrlMallocArg);
|
||||
using CellPngDecCbControlFree = s32(vm::ptr<void> ptr, vm::ptr<void> cbCtrlFreeArg);
|
||||
using CellPngDecCbControlFree = s32(vm::ptr<void> ptr, vm::ptr<void> cbCtrlFreeArg);
|
||||
|
||||
// Structs
|
||||
struct CellPngDecThreadInParam
|
||||
@@ -179,18 +190,6 @@ struct CellPngDecDataOutInfo
|
||||
be_t<s32> status; // CellPngDecDecodeStatus
|
||||
};
|
||||
|
||||
// Defines for decoding partial streams
|
||||
enum CellPngDecBufferMode : s32
|
||||
{
|
||||
CELL_PNGDEC_LINE_MODE = 1,
|
||||
};
|
||||
|
||||
enum CellPngDecSpuMode : s32
|
||||
{
|
||||
CELL_PNGDEC_RECEIVE_EVENT = 0,
|
||||
CELL_PNGDEC_TRYRECEIVE_EVENT = 1,
|
||||
};
|
||||
|
||||
// Structs for decoding partial streams
|
||||
struct CellPngDecStrmInfo
|
||||
{
|
||||
@@ -248,7 +247,7 @@ struct CellPngDecExtOutParam
|
||||
|
||||
// Callbacks for decoding partial streams
|
||||
using CellPngDecCbControlStream = s32(vm::ptr<CellPngDecStrmInfo> strmInfo, vm::ptr<CellPngDecStrmParam> strmParam, vm::ptr<void> cbCtrlStrmArg);
|
||||
using CellPngDecCbControlDisp = s32(vm::ptr<CellPngDecDispInfo> dispInfo, vm::ptr<CellPngDecDispParam> dispParam, vm::ptr<void> cbCtrlDispArg);
|
||||
using CellPngDecCbControlDisp = s32(vm::ptr<CellPngDecDispInfo> dispInfo, vm::ptr<CellPngDecDispParam> dispParam, vm::ptr<void> cbCtrlDispArg);
|
||||
|
||||
struct CellPngDecCbCtrlStrm
|
||||
{
|
||||
@@ -263,7 +262,7 @@ struct CellPngDecCbCtrlDisp
|
||||
};
|
||||
|
||||
// Custom structs
|
||||
struct PngDecoder
|
||||
struct PngHandle
|
||||
{
|
||||
vm::ptr<CellPngDecCbControlMalloc> malloc;
|
||||
vm::ptr<void> malloc_arg;
|
||||
@@ -271,17 +270,53 @@ struct PngDecoder
|
||||
vm::ptr<void> free_arg;
|
||||
};
|
||||
|
||||
// For reading from a buffer using libpng
|
||||
struct PngBuffer
|
||||
{
|
||||
// The cursor location and data pointer for reading from a buffer
|
||||
size_t cursor;
|
||||
size_t length;
|
||||
vm::bptr<void> data;
|
||||
|
||||
// The file descriptor, and whether we need to read from a file descriptor
|
||||
bool file;
|
||||
u32 fd;
|
||||
};
|
||||
|
||||
struct PngStream
|
||||
{
|
||||
vm::ptr<PngDecoder> dec;
|
||||
|
||||
// old data:
|
||||
u32 fd;
|
||||
u64 fileSize;
|
||||
// PNG decoding structures
|
||||
CellPngDecInfo info;
|
||||
CellPngDecOutParam outParam;
|
||||
CellPngDecSrc src;
|
||||
|
||||
CellPngDecOutParam out_param;
|
||||
CellPngDecSrc source;
|
||||
CellPngDecStrmInfo streamInfo;
|
||||
CellPngDecStrmParam streamParam;
|
||||
|
||||
// Fixed alpha value and flag
|
||||
bool fixed_alpha;
|
||||
be_t<u32> fixed_alpha_colour;
|
||||
|
||||
// Pixel packing value
|
||||
be_t<s32> packing;
|
||||
|
||||
// PNG custom read function structure, for decoding from a buffer
|
||||
vm::ptr<PngBuffer> buffer;
|
||||
|
||||
// libpng structures for reading and decoding the PNG file
|
||||
png_structp png_ptr;
|
||||
png_infop info_ptr;
|
||||
};
|
||||
|
||||
// Converts libpng colour type to cellPngDec colour type
|
||||
static s32 getPngDecColourType(u8 type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case PNG_COLOR_TYPE_RGB: return CELL_PNGDEC_RGB;
|
||||
case PNG_COLOR_TYPE_RGBA: return CELL_PNGDEC_RGBA; // We can't diffrentiate between ARGB and RGBA. Doesn't seem to be exactly important.
|
||||
case PNG_COLOR_TYPE_PALETTE: return CELL_PNGDEC_PALETTE;
|
||||
case PNG_COLOR_TYPE_GRAY: return CELL_PNGDEC_GRAYSCALE;
|
||||
case PNG_COLOR_TYPE_GRAY_ALPHA: return CELL_PNGDEC_GRAYSCALE_ALPHA;
|
||||
default: throw EXCEPTION("Unknown colour type: %d", type);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -258,7 +258,7 @@ u8 RescDstFormat2SysutilFormat(u32 dstFormat)
|
||||
{
|
||||
case CELL_RESC_SURFACE_F_W16Z16Y16X16:
|
||||
return CELL_VIDEO_OUT_BUFFER_COLOR_FORMAT_R16G16B16X16_FLOAT;
|
||||
default:
|
||||
default:
|
||||
return CELL_VIDEO_OUT_BUFFER_COLOR_FORMAT_X8R8G8B8;
|
||||
}
|
||||
}
|
||||
@@ -267,24 +267,24 @@ u8 GcmSurfaceFormat2GcmTextureFormat(u8 surfaceFormat, u8 surfaceType)
|
||||
{
|
||||
u8 result = 0;
|
||||
|
||||
switch (surfaceFormat)
|
||||
switch (rsx::to_surface_color_format(surfaceFormat))
|
||||
{
|
||||
case CELL_GCM_SURFACE_A8R8G8B8:
|
||||
result = CELL_GCM_TEXTURE_A8R8G8B8;
|
||||
case rsx::surface_color_format::a8r8g8b8:
|
||||
result = CELL_GCM_TEXTURE_A8R8G8B8;
|
||||
break;
|
||||
case CELL_GCM_SURFACE_F_W16Z16Y16X16:
|
||||
result = CELL_GCM_TEXTURE_W16_Z16_Y16_X16_FLOAT;
|
||||
case rsx::surface_color_format::w16z16y16x16:
|
||||
result = CELL_GCM_TEXTURE_W16_Z16_Y16_X16_FLOAT;
|
||||
break;
|
||||
default:
|
||||
default:
|
||||
return 0xFF; //Error
|
||||
}
|
||||
|
||||
switch (surfaceType)
|
||||
{
|
||||
case CELL_GCM_SURFACE_PITCH:
|
||||
case CELL_GCM_SURFACE_PITCH:
|
||||
result |= CELL_GCM_TEXTURE_LN;
|
||||
break;
|
||||
case CELL_GCM_SURFACE_SWIZZLE:
|
||||
case CELL_GCM_SURFACE_SWIZZLE:
|
||||
result |= CELL_GCM_TEXTURE_SZ;
|
||||
break;
|
||||
default:
|
||||
@@ -300,13 +300,13 @@ s32 GetRescDestsIndex(u32 dstMode)
|
||||
{
|
||||
switch(dstMode)
|
||||
{
|
||||
case CELL_RESC_720x480:
|
||||
case CELL_RESC_720x480:
|
||||
return 0;
|
||||
case CELL_RESC_720x576:
|
||||
case CELL_RESC_720x576:
|
||||
return 1;
|
||||
case CELL_RESC_1280x720:
|
||||
case CELL_RESC_1280x720:
|
||||
return 2;
|
||||
case CELL_RESC_1920x1080:
|
||||
case CELL_RESC_1920x1080:
|
||||
return 3;
|
||||
default:
|
||||
return -1;
|
||||
@@ -317,14 +317,14 @@ void GetScreenSize(u32 mode, s32 *width, s32 *height)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case CELL_RESC_720x480:
|
||||
*width = 720; *height = 480;
|
||||
case CELL_RESC_720x480:
|
||||
*width = 720; *height = 480;
|
||||
break;
|
||||
case CELL_RESC_720x576:
|
||||
*width = 720; *height = 576;
|
||||
case CELL_RESC_720x576:
|
||||
*width = 720; *height = 576;
|
||||
break;
|
||||
case CELL_RESC_1280x720:
|
||||
*width = 1280; *height = 720;
|
||||
case CELL_RESC_1280x720:
|
||||
*width = 1280; *height = 720;
|
||||
break;
|
||||
case CELL_RESC_1920x1080:
|
||||
*width = 1920; *height = 1080;
|
||||
@@ -933,18 +933,18 @@ s32 cellRescGcmSurface2RescSrc(vm::ptr<CellGcmSurface> gcmSurface, vm::ptr<CellR
|
||||
u8 textureFormat = GcmSurfaceFormat2GcmTextureFormat(gcmSurface->colorFormat, gcmSurface->type);
|
||||
s32 xW = 1, xH = 1;
|
||||
|
||||
switch(gcmSurface->antialias)
|
||||
switch(rsx::to_surface_antialiasing(gcmSurface->antialias))
|
||||
{
|
||||
case CELL_GCM_SURFACE_SQUARE_ROTATED_4:
|
||||
case rsx::surface_antialiasing::square_rotated_4_samples:
|
||||
xW=xH=2;
|
||||
break;
|
||||
case CELL_GCM_SURFACE_SQUARE_CENTERED_4:
|
||||
case rsx::surface_antialiasing::square_centered_4_samples:
|
||||
xW=xH=2;
|
||||
break;
|
||||
case CELL_GCM_SURFACE_DIAGONAL_CENTERED_2:
|
||||
case rsx::surface_antialiasing::diagonal_centered_2_samples:
|
||||
xW=2;
|
||||
break;
|
||||
default:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -95,20 +95,19 @@ never_inline s32 savedata_op(PPUThread& ppu, u32 operation, u32 version, vm::cpt
|
||||
listGet->dirNum++;
|
||||
|
||||
// PSF parameters
|
||||
vfsFile f(base_dir + entry->name + "/PARAM.SFO");
|
||||
const PSFLoader psf(f);
|
||||
const auto& psf = psf::load(vfsFile(base_dir + entry->name + "/PARAM.SFO").VRead<char>());
|
||||
|
||||
if (!psf)
|
||||
if (psf.empty())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
SaveDataEntry save_entry2;
|
||||
save_entry2.dirName = psf.GetString("SAVEDATA_DIRECTORY");
|
||||
save_entry2.listParam = psf.GetString("SAVEDATA_LIST_PARAM");
|
||||
save_entry2.title = psf.GetString("TITLE");
|
||||
save_entry2.subtitle = psf.GetString("SUB_TITLE");
|
||||
save_entry2.details = psf.GetString("DETAIL");
|
||||
save_entry2.dirName = psf.at("SAVEDATA_DIRECTORY").as_string();
|
||||
save_entry2.listParam = psf.at("SAVEDATA_LIST_PARAM").as_string();
|
||||
save_entry2.title = psf.at("TITLE").as_string();
|
||||
save_entry2.subtitle = psf.at("SUB_TITLE").as_string();
|
||||
save_entry2.details = psf.at("DETAIL").as_string();
|
||||
|
||||
save_entry2.size = 0;
|
||||
|
||||
@@ -340,13 +339,7 @@ never_inline s32 savedata_op(PPUThread& ppu, u32 operation, u32 version, vm::cpt
|
||||
std::string dir_path = base_dir + save_entry.dirName + "/";
|
||||
std::string sfo_path = dir_path + "PARAM.SFO";
|
||||
|
||||
PSFLoader psf;
|
||||
|
||||
// Load PARAM.SFO
|
||||
{
|
||||
vfsFile f(sfo_path);
|
||||
psf.Load(f);
|
||||
}
|
||||
auto&& psf = psf::load(vfsFile(sfo_path).VRead<char>());
|
||||
|
||||
// Get save stats
|
||||
{
|
||||
@@ -361,18 +354,21 @@ never_inline s32 savedata_op(PPUThread& ppu, u32 operation, u32 version, vm::cpt
|
||||
}
|
||||
|
||||
statGet->hddFreeSizeKB = 40 * 1024 * 1024; // 40 GB
|
||||
statGet->isNewData = save_entry.isNew = !psf;
|
||||
statGet->isNewData = save_entry.isNew = psf.empty();
|
||||
|
||||
statGet->dir.atime = save_entry.atime = dir_info.atime;
|
||||
statGet->dir.mtime = save_entry.mtime = dir_info.mtime;
|
||||
statGet->dir.ctime = save_entry.ctime = dir_info.ctime;
|
||||
strcpy_trunc(statGet->dir.dirName, save_entry.dirName);
|
||||
|
||||
statGet->getParam.attribute = psf.GetInteger("ATTRIBUTE"); // ???
|
||||
strcpy_trunc(statGet->getParam.title, save_entry.title = psf.GetString("TITLE"));
|
||||
strcpy_trunc(statGet->getParam.subTitle, save_entry.subtitle = psf.GetString("SUB_TITLE"));
|
||||
strcpy_trunc(statGet->getParam.detail, save_entry.details = psf.GetString("DETAIL"));
|
||||
strcpy_trunc(statGet->getParam.listParam, save_entry.listParam = psf.GetString("SAVEDATA_LIST_PARAM"));
|
||||
if (!psf.empty())
|
||||
{
|
||||
statGet->getParam.attribute = psf.at("ATTRIBUTE").as_integer(); // ???
|
||||
strcpy_trunc(statGet->getParam.title, save_entry.title = psf.at("TITLE").as_string());
|
||||
strcpy_trunc(statGet->getParam.subTitle, save_entry.subtitle = psf.at("SUB_TITLE").as_string());
|
||||
strcpy_trunc(statGet->getParam.detail, save_entry.details = psf.at("DETAIL").as_string());
|
||||
strcpy_trunc(statGet->getParam.listParam, save_entry.listParam = psf.at("SAVEDATA_LIST_PARAM").as_string());
|
||||
}
|
||||
|
||||
statGet->bind = 0;
|
||||
statGet->sizeKB = save_entry.size / 1024;
|
||||
@@ -410,7 +406,7 @@ never_inline s32 savedata_op(PPUThread& ppu, u32 operation, u32 version, vm::cpt
|
||||
{
|
||||
file.fileType = CELL_SAVEDATA_FILETYPE_CONTENT_SND0;
|
||||
}
|
||||
else if (psf.GetInteger("*" + entry->name)) // let's put the list of protected files in PARAM.SFO (int param = 1 if protected)
|
||||
else if (psf::get_integer(psf, "*" + entry->name)) // let's put the list of protected files in PARAM.SFO (int param = 1 if protected)
|
||||
{
|
||||
file.fileType = CELL_SAVEDATA_FILETYPE_SECUREFILE;
|
||||
}
|
||||
@@ -438,22 +434,23 @@ never_inline s32 savedata_op(PPUThread& ppu, u32 operation, u32 version, vm::cpt
|
||||
|
||||
if (statSet->setParam)
|
||||
{
|
||||
psf.Clear();
|
||||
|
||||
// Update PARAM.SFO
|
||||
psf.SetString("ACCOUNT_ID", ""); // ???
|
||||
psf.SetInteger("ATTRIBUTE", statSet->setParam->attribute);
|
||||
psf.SetString("CATEGORY", "SD"); // ???
|
||||
psf.SetString("PARAMS", ""); // ???
|
||||
psf.SetString("PARAMS2", ""); // ???
|
||||
psf.SetInteger("PARENTAL_LEVEL", 0); // ???
|
||||
psf.SetString("DETAIL", statSet->setParam->detail);
|
||||
psf.SetString("SAVEDATA_DIRECTORY", save_entry.dirName);
|
||||
psf.SetString("SAVEDATA_LIST_PARAM", statSet->setParam->listParam);
|
||||
psf.SetString("SUB_TITLE", statSet->setParam->subTitle);
|
||||
psf.SetString("TITLE", statSet->setParam->title);
|
||||
psf.insert(
|
||||
{
|
||||
{ "ACCOUNT_ID", psf::array(16, "0000000000000000") }, // ???
|
||||
{ "ATTRIBUTE", statSet->setParam->attribute.value() },
|
||||
{ "CATEGORY", psf::string(4, "SD") }, // ???
|
||||
{ "PARAMS", psf::string(16, {}) }, // ???
|
||||
{ "PARAMS2", psf::string(16, {}) }, // ???
|
||||
{ "PARENTAL_LEVEL", 0 }, // ???
|
||||
{ "DETAIL", psf::string(1024, statSet->setParam->detail) },
|
||||
{ "SAVEDATA_DIRECTORY", psf::string(256, save_entry.dirName) },
|
||||
{ "SAVEDATA_LIST_PARAM", psf::string(8, statSet->setParam->listParam) },
|
||||
{ "SUB_TITLE", psf::string(128, statSet->setParam->subTitle) },
|
||||
{ "TITLE", psf::string(128, statSet->setParam->title) },
|
||||
});
|
||||
}
|
||||
else if (!psf)
|
||||
else if (psf.empty())
|
||||
{
|
||||
// setParam is NULL for new savedata: abort operation
|
||||
|
||||
@@ -505,7 +502,7 @@ never_inline s32 savedata_op(PPUThread& ppu, u32 operation, u32 version, vm::cpt
|
||||
}
|
||||
|
||||
// Create save directory if necessary
|
||||
if (psf && save_entry.isNew && !Emu.GetVFS().CreateDir(dir_path))
|
||||
if (psf.size() && save_entry.isNew && !Emu.GetVFS().CreateDir(dir_path))
|
||||
{
|
||||
// Let's ignore this error for now
|
||||
}
|
||||
@@ -572,7 +569,7 @@ never_inline s32 savedata_op(PPUThread& ppu, u32 operation, u32 version, vm::cpt
|
||||
}
|
||||
}
|
||||
|
||||
psf.SetInteger("*" + file_path, fileSet->fileType == CELL_SAVEDATA_FILETYPE_SECUREFILE);
|
||||
psf.emplace("*" + file_path, fileSet->fileType == CELL_SAVEDATA_FILETYPE_SECUREFILE);
|
||||
|
||||
std::string local_path;
|
||||
|
||||
@@ -621,10 +618,9 @@ never_inline s32 savedata_op(PPUThread& ppu, u32 operation, u32 version, vm::cpt
|
||||
}
|
||||
|
||||
// Write PARAM.SFO
|
||||
if (psf)
|
||||
if (psf.size())
|
||||
{
|
||||
vfsFile f(sfo_path, fom::rewrite);
|
||||
psf.Save(f);
|
||||
vfsFile(sfo_path, fom::rewrite).VWrite(psf::save(psf));
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
|
||||
@@ -231,9 +231,9 @@ void Emulator::Load()
|
||||
|
||||
LOG_NOTICE(LOADER, "");
|
||||
f.Open("/app_home/../PARAM.SFO");
|
||||
const PSFLoader psf(f);
|
||||
std::string title = psf.GetString("TITLE");
|
||||
std::string title_id = psf.GetString("TITLE_ID");
|
||||
const auto& psf = psf::load(f.VRead<char>());
|
||||
std::string title = psf::get_string(psf, "TITLE");
|
||||
std::string title_id = psf::get_string(psf, "TITLE_ID");
|
||||
LOG_NOTICE(LOADER, "Title: %s", title.c_str());
|
||||
LOG_NOTICE(LOADER, "Serial: %s", title_id.c_str());
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ public:
|
||||
t_name->SetForegroundColour(wxColor(255, 255, 255));
|
||||
t_name->SetPosition(wxPoint(10, 6));
|
||||
|
||||
wxStaticText* t_descr = new wxStaticText(this, wxID_ANY, "An early but promising PS3 emulator and debugger.");
|
||||
wxStaticText* t_descr = new wxStaticText(this, wxID_ANY, "A PlayStation 3 emulator and debugger.");
|
||||
t_descr->SetBackgroundColour(wxColor(100, 100, 100));
|
||||
t_descr->SetForegroundColour(wxColor(255, 255, 255));
|
||||
t_descr->SetPosition(wxPoint(12, 50));
|
||||
@@ -62,7 +62,7 @@ public:
|
||||
s_panel_buttons->AddStretchSpacer();
|
||||
s_panel_buttons->Add(b_forum, 16, 0, 5);
|
||||
s_panel_buttons->AddStretchSpacer(20);
|
||||
s_panel_buttons->Add(new wxButton(this, wxID_OK), 16, 0, 5);
|
||||
s_panel_buttons->Add(new wxButton(this, wxID_OK, "Close") , 16, 0, 5);
|
||||
s_panel_buttons->AddSpacer(12);
|
||||
|
||||
//Panels
|
||||
|
||||
@@ -5,13 +5,13 @@
|
||||
|
||||
//TODO::Get the enable configuration from ini.
|
||||
AutoPauseManagerDialog::AutoPauseManagerDialog(wxWindow* parent)
|
||||
: wxDialog(parent, wxID_ANY, "Auto Pause Manager")
|
||||
: wxDialog(parent, wxID_ANY, "Automatic pause settings")
|
||||
{
|
||||
SetMinSize(wxSize(400, 360));
|
||||
|
||||
wxBoxSizer* s_main = new wxBoxSizer(wxVERTICAL);
|
||||
|
||||
wxStaticText* s_description = new wxStaticText(this, wxID_ANY, "To use auto pause: enter the ID(s) of a function or a system call. Restart of the game is required to apply. You can enable/disable this in the settings.", wxDefaultPosition, wxDefaultSize, 0);
|
||||
wxStaticText* s_description = new wxStaticText(this, wxID_ANY, "To use auto pause: enter the ID(s) of a function or a system call. You must restart your emulated game or application for changed settings to take effect. You can enable/disable this in the settings.", wxDefaultPosition, wxDefaultSize, 0);
|
||||
s_description->Wrap(400);
|
||||
s_main->Add(s_description, 0, wxALL, 5);
|
||||
|
||||
@@ -114,11 +114,11 @@ void AutoPauseManagerDialog::UpdateList(void)
|
||||
|
||||
if (m_entries[i] < 1024)
|
||||
{
|
||||
m_list->SetItem(i, 1, "System Call");
|
||||
m_list->SetItem(i, 1, "System call");
|
||||
}
|
||||
else
|
||||
{
|
||||
m_list->SetItem(i, 1, "Function Call");
|
||||
m_list->SetItem(i, 1, "Function call");
|
||||
}
|
||||
}
|
||||
m_list->SetColumnWidth(0, wxLIST_AUTOSIZE_USEHEADER);
|
||||
@@ -176,7 +176,7 @@ void AutoPauseManagerDialog::OnRemove(wxCommandEvent& event)
|
||||
void AutoPauseManagerDialog::OnSave(wxCommandEvent& event)
|
||||
{
|
||||
SaveEntries();
|
||||
LOG_SUCCESS(HLE,"Auto Pause: File pause.bin was updated.");
|
||||
LOG_SUCCESS(HLE,"Automatic pause: file pause.bin was updated.");
|
||||
//event.Skip();
|
||||
}
|
||||
|
||||
@@ -193,7 +193,7 @@ void AutoPauseManagerDialog::OnReload(wxCommandEvent& event)
|
||||
}
|
||||
|
||||
AutoPauseSettingsDialog::AutoPauseSettingsDialog(wxWindow* parent, u32 *entry)
|
||||
: wxDialog(parent, wxID_ANY, "Auto Pause Setting")
|
||||
: wxDialog(parent, wxID_ANY, "Automatic pause Setting")
|
||||
, m_presult(entry)
|
||||
{
|
||||
m_entry = *m_presult;
|
||||
@@ -202,7 +202,7 @@ AutoPauseSettingsDialog::AutoPauseSettingsDialog(wxWindow* parent, u32 *entry)
|
||||
|
||||
wxBoxSizer* s_main = new wxBoxSizer(wxVERTICAL);
|
||||
|
||||
wxStaticText* s_description = new wxStaticText(this, wxID_ANY, "Specify ID of System Call or Function Call below. You need to use a Hexadecimal ID.", wxDefaultPosition, wxDefaultSize, 0);
|
||||
wxStaticText* s_description = new wxStaticText(this, wxID_ANY, "Specify ID of system call or function call below. You need to use a hexadecimal ID.", wxDefaultPosition, wxDefaultSize, 0);
|
||||
s_description->Wrap(400);
|
||||
s_main->Add(s_description, 0, wxALL, 5);
|
||||
|
||||
@@ -220,7 +220,7 @@ AutoPauseSettingsDialog::AutoPauseSettingsDialog(wxWindow* parent, u32 *entry)
|
||||
|
||||
m_id->SetValue(fmt::format("%08x", m_entry));
|
||||
|
||||
SetTitle("Auto Pause Setting: " + m_id->GetValue());
|
||||
SetTitle("Automatic pause setting: " + m_id->GetValue());
|
||||
|
||||
Bind(wxEVT_BUTTON, &AutoPauseSettingsDialog::OnOk, this, wxID_OK);
|
||||
Bind(wxEVT_TEXT, &AutoPauseSettingsDialog::OnUpdateValue, this, wxID_STATIC);
|
||||
|
||||
@@ -10,13 +10,13 @@ BEGIN_EVENT_TABLE(CgDisasm, wxFrame)
|
||||
END_EVENT_TABLE()
|
||||
|
||||
CgDisasm::CgDisasm(wxWindow* parent)
|
||||
: wxFrame(parent, wxID_ANY, "Cg Disasm", wxDefaultPosition, wxSize(640, 480))
|
||||
: wxFrame(parent, wxID_ANY, "Cg disassembler", wxDefaultPosition, wxSize(640, 480))
|
||||
{
|
||||
wxMenuBar* menubar = new wxMenuBar();
|
||||
|
||||
wxMenu* menu_general = new wxMenu();
|
||||
menubar->Append(menu_general, "&Open");
|
||||
menu_general->Append(id_open_file, "Open &Cg binary program");
|
||||
menubar->Append(menu_general, "&File");
|
||||
menu_general->Append(id_open_file, "Open &Cg binary");
|
||||
|
||||
wxNotebook* nb_cg = new wxNotebook(this, wxID_ANY);
|
||||
wxPanel* p_cg_disasm = new wxPanel(nb_cg, wxID_ANY);
|
||||
|
||||
@@ -19,7 +19,7 @@ wxFont GetFont(int size)
|
||||
}
|
||||
|
||||
CompilerELF::CompilerELF(wxWindow* parent)
|
||||
: FrameBase(parent, wxID_ANY, "CompilerELF", "", wxSize(640, 680))
|
||||
: FrameBase(parent, wxID_ANY, "ELF compiler", "", wxSize(640, 680))
|
||||
, m_status_bar(*CreateStatusBar())
|
||||
{
|
||||
m_disable_scroll = false;
|
||||
@@ -28,11 +28,11 @@ CompilerELF::CompilerELF(wxWindow* parent)
|
||||
|
||||
wxMenuBar* menubar = new wxMenuBar();
|
||||
wxMenu* menu_code = new wxMenu();
|
||||
menubar->Append(menu_code, "Code");
|
||||
menubar->Append(menu_code, "File");
|
||||
|
||||
//menu_code.Append(id_analyze_code, "Analyze");
|
||||
menu_code->Append(id_compile_code, "Compile");
|
||||
menu_code->Append(id_load_elf, "Load ELF");
|
||||
menu_code->Append(id_compile_code, "Compile");
|
||||
|
||||
SetMenuBar(menubar);
|
||||
asm_list = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(400, -1), wxTE_MULTILINE | wxTE_DONTWRAP | wxTE_RICH2);
|
||||
|
||||
@@ -125,7 +125,7 @@ class DumperThread : public ThreadBase
|
||||
wxArrayString** arr;
|
||||
|
||||
public:
|
||||
DumperThread() : ThreadBase("DumperThread")
|
||||
DumperThread() : ThreadBase("Dumper thread")
|
||||
{
|
||||
}
|
||||
|
||||
@@ -204,7 +204,7 @@ struct WaitDumperThread : public ThreadBase
|
||||
wxArrayString** arr;
|
||||
|
||||
WaitDumperThread(bool* _done, u8 _cores, wxString _patch, MTProgressDialog& _prog_dial, wxArrayString** _arr)
|
||||
: ThreadBase("WaitDumperThread")
|
||||
: ThreadBase("Wait dumper thread")
|
||||
, done(_done)
|
||||
, cores(_cores)
|
||||
, patch(_patch)
|
||||
|
||||
@@ -10,7 +10,7 @@ protected:
|
||||
FrameBase(
|
||||
wxWindow* parent,
|
||||
wxWindowID id = wxID_ANY,
|
||||
const wxString& framename = "UnknownFrame",
|
||||
const wxString& framename = "Unknown frame",
|
||||
const std::string& ininame = "",
|
||||
wxSize defsize = wxDefaultSize,
|
||||
wxPoint defposition = wxDefaultPosition,
|
||||
|
||||
+11
-17
@@ -10,7 +10,7 @@
|
||||
#include "Loader/PSF.h"
|
||||
#include "SettingsDialog.h"
|
||||
|
||||
static const std::string m_class_name = "GameViewer";
|
||||
static const std::string m_class_name = "Game viewer";
|
||||
|
||||
// Auxiliary classes
|
||||
class sortGameData
|
||||
@@ -105,18 +105,12 @@ void GameViewer::LoadPSF()
|
||||
}
|
||||
|
||||
vfsFile f;
|
||||
|
||||
if (!f.Open(sfo))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const PSFLoader psf(f);
|
||||
|
||||
if (!psf)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
const auto& psf = psf::load(f.VRead<char>());
|
||||
|
||||
// get local path from VFS...
|
||||
std::string local_path;
|
||||
@@ -124,14 +118,14 @@ void GameViewer::LoadPSF()
|
||||
|
||||
GameInfo game;
|
||||
game.root = m_games[i];
|
||||
game.serial = psf.GetString("TITLE_ID");
|
||||
game.name = psf.GetString("TITLE");
|
||||
game.app_ver = psf.GetString("APP_VER");
|
||||
game.category = psf.GetString("CATEGORY");
|
||||
game.fw = psf.GetString("PS3_SYSTEM_VER");
|
||||
game.parental_lvl = psf.GetInteger("PARENTAL_LEVEL");
|
||||
game.resolution = psf.GetInteger("RESOLUTION");
|
||||
game.sound_format = psf.GetInteger("SOUND_FORMAT");
|
||||
game.serial = psf::get_string(psf, "TITLE_ID", "unknown");
|
||||
game.name = psf::get_string(psf, "TITLE", "unknown");
|
||||
game.app_ver = psf::get_string(psf, "APP_VER", "unknown");
|
||||
game.category = psf::get_string(psf, "CATEGORY", "unknown");
|
||||
game.fw = psf::get_string(psf, "PS3_SYSTEM_VER", "unknown");
|
||||
game.parental_lvl = psf::get_integer(psf, "PARENTAL_LEVEL");
|
||||
game.resolution = psf::get_integer(psf, "RESOLUTION");
|
||||
game.sound_format = psf::get_integer(psf, "SOUND_FORMAT");
|
||||
|
||||
if (game.serial.length() == 9)
|
||||
{
|
||||
@@ -236,7 +230,7 @@ void GameViewer::RightClick(wxListEvent& event)
|
||||
#endif
|
||||
m_popup->Append(boot_item);
|
||||
m_popup->Append(1, _T("Configure"));
|
||||
m_popup->Append(2, _T("Remove Game"));
|
||||
m_popup->Append(2, _T("Remove game"));
|
||||
|
||||
Bind(wxEVT_MENU, &GameViewer::BootGame, this, 0);
|
||||
Bind(wxEVT_MENU, &GameViewer::ConfigureGame, this, 1);
|
||||
|
||||
@@ -85,12 +85,12 @@ public:
|
||||
m_img_list = new wxImageList(80, 44);
|
||||
|
||||
m_columns.clear();
|
||||
m_columns.emplace_back(m_columns.size(), 90, "Icon");
|
||||
m_columns.emplace_back(m_columns.size(), 90, "");
|
||||
m_columns.emplace_back(m_columns.size(), 160, "Name");
|
||||
m_columns.emplace_back(m_columns.size(), 85, "Serial");
|
||||
m_columns.emplace_back(m_columns.size(), 55, "FW");
|
||||
m_columns.emplace_back(m_columns.size(), 55, "App version");
|
||||
m_columns.emplace_back(m_columns.size(), 75, "Category");
|
||||
m_columns.emplace_back(m_columns.size(), 60, "Min. FW");
|
||||
m_columns.emplace_back(m_columns.size(), 80, "Soft. version");
|
||||
m_columns.emplace_back(m_columns.size(), 75, "Soft. type");
|
||||
m_columns.emplace_back(m_columns.size(), 160, "Path");
|
||||
m_col_icon = &m_columns[0];
|
||||
m_col_name = &m_columns[1];
|
||||
|
||||
@@ -34,8 +34,8 @@ InterpreterDisAsmFrame::InterpreterDisAsmFrame(wxWindow* parent)
|
||||
m_list = new wxListView(this);
|
||||
m_choice_units = new wxChoice(this, wxID_ANY);
|
||||
|
||||
wxButton* b_go_to_addr = new wxButton(this, wxID_ANY, "Go To Address");
|
||||
wxButton* b_go_to_pc = new wxButton(this, wxID_ANY, "Go To PC");
|
||||
wxButton* b_go_to_addr = new wxButton(this, wxID_ANY, "Go to address");
|
||||
wxButton* b_go_to_pc = new wxButton(this, wxID_ANY, "Go to PC");
|
||||
|
||||
m_btn_step = new wxButton(this, wxID_ANY, "Step");
|
||||
m_btn_run = new wxButton(this, wxID_ANY, "Run");
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#include "KernelExplorer.h"
|
||||
|
||||
KernelExplorer::KernelExplorer(wxWindow* parent)
|
||||
: wxDialog(parent, wxID_ANY, "Kernel Explorer", wxDefaultPosition, wxSize(700, 450))
|
||||
: wxDialog(parent, wxID_ANY, "Kernel explorer", wxDefaultPosition, wxSize(700, 450))
|
||||
{
|
||||
this->SetBackgroundColour(wxColour(240,240,240)); //This fix the ugly background color under Windows
|
||||
wxBoxSizer* s_panel = new wxBoxSizer(wxVERTICAL);
|
||||
@@ -59,7 +59,7 @@ void KernelExplorer::Update()
|
||||
m_tree->DeleteAllItems();
|
||||
const u32 total_memory_usage = vm::get(vm::user_space)->used.load();
|
||||
|
||||
const auto& root = m_tree->AddRoot(fmt::format("Process, ID = 0x00000001, Total Memory Usage = 0x%x (%0.2f MB)", total_memory_usage, (float)total_memory_usage / (1024 * 1024)));
|
||||
const auto& root = m_tree->AddRoot(fmt::format("Process, ID = 0x00000001, Total memory usage = 0x%x (%0.2f MB)", total_memory_usage, (float)total_memory_usage / (1024 * 1024)));
|
||||
|
||||
union name64
|
||||
{
|
||||
@@ -116,7 +116,7 @@ void KernelExplorer::Update()
|
||||
|
||||
if (lwm_map.size())
|
||||
{
|
||||
const auto& node = m_tree->AppendItem(root, fmt::format("Lightweight Mutexes (%zu)", lwm_map.size()));
|
||||
const auto& node = m_tree->AppendItem(root, fmt::format("Lightweight mutexes (%zu)", lwm_map.size()));
|
||||
|
||||
for (const auto& data : lwm_map)
|
||||
{
|
||||
@@ -132,7 +132,7 @@ void KernelExplorer::Update()
|
||||
|
||||
if (cond_map.size())
|
||||
{
|
||||
const auto& node = m_tree->AppendItem(root, fmt::format("Condition Variables (%zu)", cond_map.size()));
|
||||
const auto& node = m_tree->AppendItem(root, fmt::format("Condition variables (%zu)", cond_map.size()));
|
||||
|
||||
for (const auto& data : cond_map)
|
||||
{
|
||||
@@ -148,7 +148,7 @@ void KernelExplorer::Update()
|
||||
|
||||
if (lwc_map.size())
|
||||
{
|
||||
const auto& node = m_tree->AppendItem(root, fmt::format("Lightweight Condition Variables (%zu)", lwc_map.size()));
|
||||
const auto& node = m_tree->AppendItem(root, fmt::format("Lightweight condition variables (%zu)", lwc_map.size()));
|
||||
|
||||
for (const auto& data : lwc_map)
|
||||
{
|
||||
@@ -164,7 +164,7 @@ void KernelExplorer::Update()
|
||||
|
||||
if (eq_map.size())
|
||||
{
|
||||
const auto& node = m_tree->AppendItem(root, fmt::format("Event Queues (%zu)", eq_map.size()));
|
||||
const auto& node = m_tree->AppendItem(root, fmt::format("Event queues (%zu)", eq_map.size()));
|
||||
|
||||
for (const auto& data : eq_map)
|
||||
{
|
||||
@@ -180,13 +180,13 @@ void KernelExplorer::Update()
|
||||
|
||||
if (ep_map.size())
|
||||
{
|
||||
const auto& node = m_tree->AppendItem(root, fmt::format("Event Ports (%zu)", ep_map.size()));
|
||||
const auto& node = m_tree->AppendItem(root, fmt::format("Event ports (%zu)", ep_map.size()));
|
||||
|
||||
for (const auto& data : ep_map)
|
||||
{
|
||||
const auto& ep = *data.second;
|
||||
|
||||
m_tree->AppendItem(node, fmt::format("Event Port: ID = 0x%08x, Name = %#llx", data.first,
|
||||
m_tree->AppendItem(node, fmt::format("Event port: ID = 0x%08x, Name = %#llx", data.first,
|
||||
ep.name));
|
||||
}
|
||||
}
|
||||
@@ -196,13 +196,13 @@ void KernelExplorer::Update()
|
||||
|
||||
if (ef_map.size())
|
||||
{
|
||||
const auto& node = m_tree->AppendItem(root, fmt::format("Event Flags (%zu)", ef_map.size()));
|
||||
const auto& node = m_tree->AppendItem(root, fmt::format("Event flags (%zu)", ef_map.size()));
|
||||
|
||||
for (const auto& data : ef_map)
|
||||
{
|
||||
const auto& ef = *data.second;
|
||||
|
||||
m_tree->AppendItem(node, fmt::format("Event Flag: ID = 0x%08x", data.first));
|
||||
m_tree->AppendItem(node, fmt::format("Event flag: ID = 0x%08x", data.first));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -211,7 +211,7 @@ void KernelExplorer::Update()
|
||||
|
||||
if (rwlock_map.size())
|
||||
{
|
||||
const auto& node = m_tree->AppendItem(root, fmt::format("Reader/writer Locks (%zu)", rwlock_map.size()));
|
||||
const auto& node = m_tree->AppendItem(root, fmt::format("Reader/writer locks (%zu)", rwlock_map.size()));
|
||||
|
||||
for (const auto& data : rwlock_map)
|
||||
{
|
||||
@@ -226,7 +226,7 @@ void KernelExplorer::Update()
|
||||
|
||||
if (prx_map.size())
|
||||
{
|
||||
const auto& node = m_tree->AppendItem(root, fmt::format("PRX Libraries (%zu)", prx_map.size()));
|
||||
const auto& node = m_tree->AppendItem(root, fmt::format("PRX libraries (%zu)", prx_map.size()));
|
||||
|
||||
for (const auto& data : prx_map)
|
||||
{
|
||||
@@ -241,13 +241,13 @@ void KernelExplorer::Update()
|
||||
|
||||
if (ct_map.size())
|
||||
{
|
||||
const auto& node = m_tree->AppendItem(root, fmt::format("Memory Containers (%zu)", ct_map.size()));
|
||||
const auto& node = m_tree->AppendItem(root, fmt::format("Memory containers (%zu)", ct_map.size()));
|
||||
|
||||
for (const auto& data : ct_map)
|
||||
{
|
||||
const auto& ct = *data.second;
|
||||
|
||||
m_tree->AppendItem(node, fmt::format("Memory Container: ID = 0x%08x", data.first));
|
||||
m_tree->AppendItem(node, fmt::format("Memory container: ID = 0x%08x", data.first));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -256,13 +256,13 @@ void KernelExplorer::Update()
|
||||
|
||||
if (mem_map.size())
|
||||
{
|
||||
const auto& node = m_tree->AppendItem(root, fmt::format("Memory Objects (%zu)", mem_map.size()));
|
||||
const auto& node = m_tree->AppendItem(root, fmt::format("Memory objects (%zu)", mem_map.size()));
|
||||
|
||||
for (const auto& data : mem_map)
|
||||
{
|
||||
const auto& mem = *data.second;
|
||||
|
||||
m_tree->AppendItem(node, fmt::format("Memory Object: ID = 0x%08x", data.first));
|
||||
m_tree->AppendItem(node, fmt::format("Memory object: ID = 0x%08x", data.first));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -271,13 +271,13 @@ void KernelExplorer::Update()
|
||||
|
||||
if (ppu_map.size())
|
||||
{
|
||||
const auto& node = m_tree->AppendItem(root, fmt::format("PPU Threads (%zu)", ppu_map.size()));
|
||||
const auto& node = m_tree->AppendItem(root, fmt::format("PPU threads (%zu)", ppu_map.size()));
|
||||
|
||||
for (const auto& data : ppu_map)
|
||||
{
|
||||
const auto& ppu = *data.second;
|
||||
|
||||
m_tree->AppendItem(node, fmt::format("PPU Thread: ID = 0x%08x '%s', - %s", data.first,
|
||||
m_tree->AppendItem(node, fmt::format("PPU thread: ID = 0x%08x '%s', - %s", data.first,
|
||||
ppu.get_name().c_str(), ppu.ThreadStatusToString()));
|
||||
}
|
||||
}
|
||||
@@ -287,13 +287,13 @@ void KernelExplorer::Update()
|
||||
|
||||
if (spu_map.size())
|
||||
{
|
||||
const auto& node = m_tree->AppendItem(root, fmt::format("SPU Thread Groups (%d)", spu_map.size()));
|
||||
const auto& node = m_tree->AppendItem(root, fmt::format("SPU thread groups (%d)", spu_map.size()));
|
||||
|
||||
for (const auto& data : spu_map)
|
||||
{
|
||||
const auto& tg = *data.second;
|
||||
|
||||
m_tree->AppendItem(node, fmt::format("SPU Thread Group: ID = 0x%08x '%s'", data.first,
|
||||
m_tree->AppendItem(node, fmt::format("SPU thread group: ID = 0x%08x '%s'", data.first,
|
||||
tg.name.c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#include "Emu/FS/VFS.h"
|
||||
|
||||
LLEModulesManagerFrame::LLEModulesManagerFrame(wxWindow* parent)
|
||||
: wxDialog(parent, wxID_ANY, "LLEModulesManagerFrame", wxDefaultPosition, wxSize(480, 640))
|
||||
: wxDialog(parent, wxID_ANY, "Modules LLE manager", wxDefaultPosition, wxSize(480, 640))
|
||||
{
|
||||
wxBoxSizer *s_panel = new wxBoxSizer(wxVERTICAL);
|
||||
wxBoxSizer *s_p_panel = new wxBoxSizer(wxVERTICAL);
|
||||
@@ -18,8 +18,8 @@ LLEModulesManagerFrame::LLEModulesManagerFrame(wxWindow* parent)
|
||||
|
||||
// select / unselect
|
||||
wxStaticBoxSizer* s_selection = new wxStaticBoxSizer(wxHORIZONTAL, p_main);
|
||||
wxButton* b_select = new wxButton(p_main, wxID_ANY, "Select All", wxDefaultPosition, wxSize(80, -1));
|
||||
wxButton* b_unselect = new wxButton(p_main, wxID_ANY, "Unselect All", wxDefaultPosition, wxSize(80, -1));
|
||||
wxButton* b_select = new wxButton(p_main, wxID_ANY, "Select all", wxDefaultPosition, wxSize(80, -1));
|
||||
wxButton* b_unselect = new wxButton(p_main, wxID_ANY, "Unselect all", wxDefaultPosition, wxSize(80, -1));
|
||||
s_selection->Add(b_select);
|
||||
s_selection->Add(b_unselect);
|
||||
|
||||
|
||||
+18
-18
@@ -77,7 +77,7 @@ MainFrame::MainFrame()
|
||||
wxMenuBar* menubar = new wxMenuBar();
|
||||
|
||||
wxMenu* menu_boot = new wxMenu();
|
||||
menubar->Append(menu_boot, "&Boot");
|
||||
menubar->Append(menu_boot, "&File");
|
||||
menu_boot->Append(id_boot_elf, "Boot &ELF / SELF file");
|
||||
menu_boot->Append(id_boot_game, "Boot &game");
|
||||
menu_boot->AppendSeparator();
|
||||
@@ -90,30 +90,30 @@ MainFrame::MainFrame()
|
||||
menu_sys->Append(id_sys_pause, "&Pause")->Enable(false);
|
||||
menu_sys->Append(id_sys_stop, "&Stop\tCtrl + S")->Enable(false);
|
||||
menu_sys->AppendSeparator();
|
||||
menu_sys->Append(id_sys_send_open_menu, "Send &open system menu cmd")->Enable(false);
|
||||
menu_sys->Append(id_sys_send_open_menu, "Press &PS button")->Enable(false);
|
||||
menu_sys->Append(id_sys_send_exit, "Send &exit cmd")->Enable(false);
|
||||
|
||||
wxMenu* menu_conf = new wxMenu();
|
||||
menubar->Append(menu_conf, "&Config");
|
||||
menu_conf->Append(id_config_emu, "&Settings");
|
||||
menu_conf->Append(id_config_pad, "&PAD Settings");
|
||||
menu_conf->Append(id_config_pad, "&Controller settings");
|
||||
menu_conf->AppendSeparator();
|
||||
menu_conf->Append(id_config_autopause_manager, "&Auto Pause Settings");
|
||||
menu_conf->Append(id_config_autopause_manager, "&Auto pause settings");
|
||||
menu_conf->AppendSeparator();
|
||||
menu_conf->Append(id_config_vfs_manager, "Virtual &File System Manager");
|
||||
menu_conf->Append(id_config_vhdd_manager, "Virtual &HDD Manager");
|
||||
menu_conf->Append(id_config_savedata_manager, "Save &Data Utility");
|
||||
menu_conf->Append(id_config_lle_modules_manager, "&LLE Modules Manager");
|
||||
menu_conf->Append(id_config_vfs_manager, "Virtual &file system manager");
|
||||
menu_conf->Append(id_config_vhdd_manager, "Virtual &hard drive manager");
|
||||
menu_conf->Append(id_config_savedata_manager, "Save &data manager");
|
||||
menu_conf->Append(id_config_lle_modules_manager, "Modules &LLE manager");
|
||||
|
||||
|
||||
wxMenu* menu_tools = new wxMenu();
|
||||
menubar->Append(menu_tools, "&Tools");
|
||||
menu_tools->Append(id_tools_compiler, "&ELF Compiler");
|
||||
menu_tools->Append(id_tools_kernel_explorer, "&Kernel Explorer")->Enable(false);
|
||||
menu_tools->Append(id_tools_memory_viewer, "&Memory Viewer")->Enable(false);
|
||||
menu_tools->Append(id_tools_rsx_debugger, "&RSX Debugger")->Enable(false);
|
||||
menu_tools->Append(id_tools_string_search, "&String Search")->Enable(false);
|
||||
menu_tools->Append(id_tools_cg_disasm, "&Cg Disasm")->Enable();
|
||||
menu_tools->Append(id_tools_compiler, "&ELF compiler");
|
||||
menu_tools->Append(id_tools_kernel_explorer, "&Kernel explorer")->Enable(false);
|
||||
menu_tools->Append(id_tools_memory_viewer, "&Memory viewer")->Enable(false);
|
||||
menu_tools->Append(id_tools_rsx_debugger, "&RSX debugger")->Enable(false);
|
||||
menu_tools->Append(id_tools_string_search, "&String search")->Enable(false);
|
||||
menu_tools->Append(id_tools_cg_disasm, "&Cg disassembler")->Enable();
|
||||
|
||||
wxMenu* menu_help = new wxMenu();
|
||||
menubar->Append(menu_help, "&Help");
|
||||
@@ -127,7 +127,7 @@ MainFrame::MainFrame()
|
||||
m_game_viewer = new GameViewer(this);
|
||||
m_debugger_frame = new DebuggerPanel(this);
|
||||
|
||||
AddPane(m_game_viewer, "Game List", wxAUI_DOCK_CENTRE);
|
||||
AddPane(m_game_viewer, "PS3 software", wxAUI_DOCK_CENTRE);
|
||||
AddPane(m_log_frame, "Log", wxAUI_DOCK_BOTTOM);
|
||||
AddPane(m_debugger_frame, "Debugger", wxAUI_DOCK_RIGHT);
|
||||
|
||||
@@ -530,7 +530,7 @@ void MainFrame::UpdateUI(wxCommandEvent& event)
|
||||
// Emulation
|
||||
wxMenuItem& pause = *menubar.FindItem(id_sys_pause);
|
||||
wxMenuItem& stop = *menubar.FindItem(id_sys_stop);
|
||||
pause.SetItemLabel(is_running ? "&Pause\tCtrl + P" : is_ready ? "&Start\tCtrl + E" : "&Resume\tCtrl + E");
|
||||
pause.SetItemLabel(is_running ? "&Pause\tCtrl + P" : is_ready ? "&Start\tCtrl + F" : "&Resume\tCtrl + F");
|
||||
pause.Enable(!is_stopped);
|
||||
stop.Enable(!is_stopped);
|
||||
|
||||
@@ -538,7 +538,7 @@ void MainFrame::UpdateUI(wxCommandEvent& event)
|
||||
wxMenuItem& send_exit = *menubar.FindItem(id_sys_send_exit);
|
||||
wxMenuItem& send_open_menu = *menubar.FindItem(id_sys_send_open_menu);
|
||||
bool enable_commands = !is_stopped;
|
||||
send_open_menu.SetItemLabel(wxString::Format("Send &%s system menu cmd", (m_sys_menu_opened ? "close" : "open")));
|
||||
send_open_menu.SetItemLabel(wxString::Format("Press &PS buton %s", (m_sys_menu_opened ? "close" : "open")));
|
||||
send_open_menu.Enable(enable_commands);
|
||||
send_exit.Enable(enable_commands);
|
||||
|
||||
@@ -565,7 +565,7 @@ void MainFrame::OnKeyDown(wxKeyEvent& event)
|
||||
{
|
||||
switch(event.GetKeyCode())
|
||||
{
|
||||
case 'E': case 'e': if(Emu.IsPaused()) Emu.Resume(); else if(Emu.IsReady()) Emu.Run(); return;
|
||||
case 'F': case 'f': if(Emu.IsPaused()) Emu.Resume(); else if(Emu.IsReady()) Emu.Run(); return;
|
||||
case 'P': case 'p': if(Emu.IsRunning()) Emu.Pause(); return;
|
||||
case 'S': case 's': if(!Emu.IsStopped()) Emu.Stop(); return;
|
||||
case 'R': case 'r': if(!Emu.GetPath().empty()) {Emu.Stop(); Emu.Run();} return;
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include "MemoryStringSearcher.h"
|
||||
|
||||
MemoryStringSearcher::MemoryStringSearcher(wxWindow* parent)
|
||||
: wxDialog(parent, wxID_ANY, "String Searcher", wxDefaultPosition, wxSize(545, 64))
|
||||
: wxDialog(parent, wxID_ANY, "String searcher", wxDefaultPosition, wxSize(545, 64))
|
||||
, exit(false)
|
||||
{
|
||||
this->SetBackgroundColour(wxColour(240,240,240));
|
||||
|
||||
@@ -19,7 +19,7 @@ MemoryViewerPanel::MemoryViewerPanel(wxWindow* parent)
|
||||
wxBoxSizer* s_tools = new wxBoxSizer(wxHORIZONTAL);
|
||||
|
||||
//Tools: Memory Viewer Options
|
||||
wxStaticBoxSizer* s_tools_mem = new wxStaticBoxSizer(wxHORIZONTAL, this, "Memory Viewer Options");
|
||||
wxStaticBoxSizer* s_tools_mem = new wxStaticBoxSizer(wxHORIZONTAL, this, "Memory viewer options");
|
||||
|
||||
wxStaticBoxSizer* s_tools_mem_addr = new wxStaticBoxSizer(wxHORIZONTAL, this, "Address");
|
||||
t_addr = new wxTextCtrl(this, wxID_ANY, "00000000", wxDefaultPosition, wxSize(60, -1), wxTE_PROCESS_ENTER);
|
||||
@@ -46,7 +46,7 @@ MemoryViewerPanel::MemoryViewerPanel(wxWindow* parent)
|
||||
s_tools_mem->Add(s_tools_mem_buttons);
|
||||
|
||||
//Tools: Raw Image Preview Options
|
||||
wxStaticBoxSizer* s_tools_img = new wxStaticBoxSizer(wxHORIZONTAL, this, "Raw Image Preview");
|
||||
wxStaticBoxSizer* s_tools_img = new wxStaticBoxSizer(wxHORIZONTAL, this, "Raw image preview");
|
||||
|
||||
wxStaticBoxSizer* s_tools_img_size = new wxStaticBoxSizer(wxHORIZONTAL, this, "Size");
|
||||
sc_img_size_x = new wxSpinCtrl(this, wxID_ANY, "256", wxDefaultPosition, wxSize(60, -1));
|
||||
@@ -223,7 +223,7 @@ void MemoryViewerPanel::ShowMemory()
|
||||
|
||||
void MemoryViewerPanel::ShowImage(wxWindow* parent, u32 addr, int mode, u32 width, u32 height, bool flipv)
|
||||
{
|
||||
wxString title = wxString::Format("Raw Image @ 0x%x", addr);
|
||||
wxString title = wxString::Format("Raw image @ 0x%x", addr);
|
||||
|
||||
wxDialog* f_image_viewer = new wxDialog(parent, wxID_ANY, title, wxDefaultPosition, wxDefaultSize, wxMINIMIZE_BOX | wxCLOSE_BOX | wxCAPTION | wxCLIP_CHILDREN);
|
||||
f_image_viewer->SetBackgroundColour(wxColour(240,240,240)); //This fix the ugly background color under Windows
|
||||
|
||||
+14
-14
@@ -7,7 +7,7 @@
|
||||
#include "PADManager.h"
|
||||
|
||||
PADManager::PADManager(wxWindow* parent)
|
||||
: wxDialog(parent, wxID_ANY, "PAD Settings")
|
||||
: wxDialog(parent, wxID_ANY, "Controller settings")
|
||||
, m_button_id(0)
|
||||
, m_key_pressed(false)
|
||||
, m_emu_paused(false)
|
||||
@@ -22,20 +22,20 @@ PADManager::PADManager(wxWindow* parent)
|
||||
wxBoxSizer* s_subpanel = new wxBoxSizer(wxVERTICAL);
|
||||
wxBoxSizer* s_subpanel2 = new wxBoxSizer(wxVERTICAL);
|
||||
|
||||
// Left Analog Stick
|
||||
wxStaticBoxSizer* s_round_stick_l = new wxStaticBoxSizer(wxVERTICAL, this, _("Left Analog Stick"));
|
||||
// Left analog stick
|
||||
wxStaticBoxSizer* s_round_stick_l = new wxStaticBoxSizer(wxVERTICAL, this, _("Left analog stick"));
|
||||
wxBoxSizer* s_subpanel_lstick_1 = new wxBoxSizer(wxVERTICAL);
|
||||
wxBoxSizer* s_subpanel_lstick_2 = new wxBoxSizer(wxHORIZONTAL);
|
||||
wxBoxSizer* s_subpanel_lstick_3 = new wxBoxSizer(wxVERTICAL);
|
||||
|
||||
// D-Pad
|
||||
wxStaticBoxSizer* s_round_pad_controls = new wxStaticBoxSizer(wxVERTICAL, this, _("D-Pad"));
|
||||
// Directional pad
|
||||
wxStaticBoxSizer* s_round_pad_controls = new wxStaticBoxSizer(wxVERTICAL, this, _("Directional pad"));
|
||||
wxBoxSizer* s_subpanel_pad_1 = new wxBoxSizer(wxVERTICAL);
|
||||
wxBoxSizer* s_subpanel_pad_2 = new wxBoxSizer(wxHORIZONTAL);
|
||||
wxBoxSizer* s_subpanel_pad_3 = new wxBoxSizer(wxVERTICAL);
|
||||
|
||||
// Left shifts
|
||||
wxStaticBoxSizer* s_round_pad_shifts_l = new wxStaticBoxSizer(wxVERTICAL, this, _("Left Shifts"));
|
||||
// L buttons
|
||||
wxStaticBoxSizer* s_round_pad_shifts_l = new wxStaticBoxSizer(wxVERTICAL, this, _("L buttons"));
|
||||
wxStaticBoxSizer* s_round_pad_l1 = new wxStaticBoxSizer(wxVERTICAL, this, _("L1"));
|
||||
wxStaticBoxSizer* s_round_pad_l2 = new wxStaticBoxSizer(wxVERTICAL, this, _("L2"));
|
||||
wxStaticBoxSizer* s_round_pad_l3 = new wxStaticBoxSizer(wxVERTICAL, this, _("L3"));
|
||||
@@ -45,8 +45,8 @@ PADManager::PADManager(wxWindow* parent)
|
||||
wxStaticBoxSizer* s_round_pad_select = new wxStaticBoxSizer(wxVERTICAL, this, _("Select"));
|
||||
wxStaticBoxSizer* s_round_pad_start = new wxStaticBoxSizer(wxVERTICAL, this, _("Start"));
|
||||
|
||||
// Right shifts
|
||||
wxStaticBoxSizer* s_round_pad_shifts_r = new wxStaticBoxSizer(wxVERTICAL, this, _("Right Shifts"));
|
||||
// R buttons
|
||||
wxStaticBoxSizer* s_round_pad_shifts_r = new wxStaticBoxSizer(wxVERTICAL, this, _("R buttons"));
|
||||
wxStaticBoxSizer* s_round_pad_r1 = new wxStaticBoxSizer(wxVERTICAL, this, _("R1"));
|
||||
wxStaticBoxSizer* s_round_pad_r2 = new wxStaticBoxSizer(wxVERTICAL, this, _("R2"));
|
||||
wxStaticBoxSizer* s_round_pad_r3 = new wxStaticBoxSizer(wxVERTICAL, this, _("R3"));
|
||||
@@ -61,8 +61,8 @@ PADManager::PADManager(wxWindow* parent)
|
||||
wxBoxSizer* s_subpanel_buttons_2 = new wxBoxSizer(wxHORIZONTAL);
|
||||
wxBoxSizer* s_subpanel_buttons_3 = new wxBoxSizer(wxVERTICAL);
|
||||
|
||||
// Right Analog Stick
|
||||
wxStaticBoxSizer* s_round_stick_r = new wxStaticBoxSizer(wxVERTICAL, this, _("Right Analog Stick"));
|
||||
// Right analog stick
|
||||
wxStaticBoxSizer* s_round_stick_r = new wxStaticBoxSizer(wxVERTICAL, this, _("Right analog stick"));
|
||||
wxBoxSizer* s_subpanel_rstick_1 = new wxBoxSizer(wxVERTICAL);
|
||||
wxBoxSizer* s_subpanel_rstick_2 = new wxBoxSizer(wxHORIZONTAL);
|
||||
wxBoxSizer* s_subpanel_rstick_3 = new wxBoxSizer(wxVERTICAL);
|
||||
@@ -123,13 +123,13 @@ PADManager::PADManager(wxWindow* parent)
|
||||
s_subpanel_lstick_2->Add(b_right_lstick);
|
||||
s_subpanel_lstick_3->Add(b_down_lstick);
|
||||
|
||||
// D-Pad
|
||||
// Directional pad
|
||||
s_subpanel_pad_1->Add(b_up);
|
||||
s_subpanel_pad_2->Add(b_left);
|
||||
s_subpanel_pad_2->Add(b_right);
|
||||
s_subpanel_pad_3->Add(b_down);
|
||||
|
||||
// Left shifts
|
||||
// L button
|
||||
s_round_pad_l1->Add(b_shift_l1);
|
||||
s_round_pad_l2->Add(b_shift_l2);
|
||||
s_round_pad_l3->Add(b_shift_l3);
|
||||
@@ -138,7 +138,7 @@ PADManager::PADManager(wxWindow* parent)
|
||||
s_round_pad_select->Add(b_select);
|
||||
s_round_pad_start->Add(b_start);
|
||||
|
||||
// Right shifts
|
||||
// R button
|
||||
s_round_pad_r1->Add(b_shift_r1);
|
||||
s_round_pad_r2->Add(b_shift_r2);
|
||||
s_round_pad_r3->Add(b_shift_r3);
|
||||
|
||||
+144
-68
@@ -25,7 +25,7 @@ enum GCMEnumTypes
|
||||
};
|
||||
|
||||
RSXDebugger::RSXDebugger(wxWindow* parent)
|
||||
: wxDialog(parent, wxID_ANY, "RSX Debugger", wxDefaultPosition, wxSize(700, 450))
|
||||
: wxDialog(parent, wxID_ANY, "RSX debugger", wxDefaultPosition, wxSize(700, 450))
|
||||
, m_item_count(37)
|
||||
, m_addr(0x0)
|
||||
, m_cur_texture(0)
|
||||
@@ -38,7 +38,7 @@ RSXDebugger::RSXDebugger(wxWindow* parent)
|
||||
wxBoxSizer* s_tools = new wxBoxSizer(wxVERTICAL);
|
||||
|
||||
// Controls
|
||||
wxStaticBoxSizer* s_controls = new wxStaticBoxSizer(wxHORIZONTAL, this, "RSX Debugger Controls");
|
||||
wxStaticBoxSizer* s_controls = new wxStaticBoxSizer(wxHORIZONTAL, this, "RSX debugger controls");
|
||||
|
||||
// Controls: Address
|
||||
wxStaticBoxSizer* s_controls_addr = new wxStaticBoxSizer(wxHORIZONTAL, this, "Address:");
|
||||
@@ -89,9 +89,9 @@ RSXDebugger::RSXDebugger(wxWindow* parent)
|
||||
wxPanel* p_texture = new wxPanel(nb_rsx, wxID_ANY);
|
||||
wxPanel* p_settings = new wxPanel(nb_rsx, wxID_ANY);
|
||||
|
||||
nb_rsx->AddPage(p_commands, wxT("RSX Commands"));
|
||||
nb_rsx->AddPage(p_captured_frame, wxT("Captured Frame"));
|
||||
nb_rsx->AddPage(p_captured_draw_calls, wxT("Captured Draw Calls"));
|
||||
nb_rsx->AddPage(p_commands, wxT("RSX commands"));
|
||||
nb_rsx->AddPage(p_captured_frame, wxT("Captured frame"));
|
||||
nb_rsx->AddPage(p_captured_draw_calls, wxT("Captured draw calls"));
|
||||
nb_rsx->AddPage(p_flags, wxT("Flags"));
|
||||
|
||||
nb_rsx->AddPage(p_lightning, wxT("Lightning"));
|
||||
@@ -177,12 +177,12 @@ RSXDebugger::RSXDebugger(wxWindow* parent)
|
||||
//Buffers
|
||||
wxBoxSizer* s_buffers1 = new wxBoxSizer(wxVERTICAL);
|
||||
wxBoxSizer* s_buffers2 = new wxBoxSizer(wxVERTICAL);
|
||||
wxStaticBoxSizer* s_buffers_colorA = new wxStaticBoxSizer(wxHORIZONTAL, p_buffers, "Color Buffer A");
|
||||
wxStaticBoxSizer* s_buffers_colorB = new wxStaticBoxSizer(wxHORIZONTAL, p_buffers, "Color Buffer B");
|
||||
wxStaticBoxSizer* s_buffers_colorC = new wxStaticBoxSizer(wxHORIZONTAL, p_buffers, "Color Buffer C");
|
||||
wxStaticBoxSizer* s_buffers_colorD = new wxStaticBoxSizer(wxHORIZONTAL, p_buffers, "Color Buffer D");
|
||||
wxStaticBoxSizer* s_buffers_depth = new wxStaticBoxSizer(wxHORIZONTAL, p_buffers, "Depth Buffer");
|
||||
wxStaticBoxSizer* s_buffers_stencil = new wxStaticBoxSizer(wxHORIZONTAL, p_buffers, "Stencil Buffer");
|
||||
wxStaticBoxSizer* s_buffers_colorA = new wxStaticBoxSizer(wxHORIZONTAL, p_buffers, "Color buffer A");
|
||||
wxStaticBoxSizer* s_buffers_colorB = new wxStaticBoxSizer(wxHORIZONTAL, p_buffers, "Color buffer B");
|
||||
wxStaticBoxSizer* s_buffers_colorC = new wxStaticBoxSizer(wxHORIZONTAL, p_buffers, "Color buffer C");
|
||||
wxStaticBoxSizer* s_buffers_colorD = new wxStaticBoxSizer(wxHORIZONTAL, p_buffers, "Color buffer D");
|
||||
wxStaticBoxSizer* s_buffers_depth = new wxStaticBoxSizer(wxHORIZONTAL, p_buffers, "Depth buffer");
|
||||
wxStaticBoxSizer* s_buffers_stencil = new wxStaticBoxSizer(wxHORIZONTAL, p_buffers, "Stencil buffer");
|
||||
wxStaticBoxSizer* s_buffers_text = new wxStaticBoxSizer(wxHORIZONTAL, p_buffers, "Texture");
|
||||
|
||||
//Buffers and textures
|
||||
@@ -251,8 +251,8 @@ RSXDebugger::RSXDebugger(wxWindow* parent)
|
||||
p_buffer_colorB->Bind(wxEVT_LEFT_DOWN, &RSXDebugger::OnClickBuffer, this);
|
||||
p_buffer_colorC->Bind(wxEVT_LEFT_DOWN, &RSXDebugger::OnClickBuffer, this);
|
||||
p_buffer_colorD->Bind(wxEVT_LEFT_DOWN, &RSXDebugger::OnClickBuffer, this);
|
||||
//p_buffer_depth->Bind(wxEVT_BUTTON, &RSXDebugger::OnClickBuffer, this);
|
||||
//p_buffer_stencil->Bind(wxEVT_BUTTON, &RSXDebugger::OnClickBuffer, this);
|
||||
p_buffer_depth->Bind(wxEVT_LEFT_DOWN, &RSXDebugger::OnClickBuffer, this);
|
||||
p_buffer_stencil->Bind(wxEVT_LEFT_DOWN, &RSXDebugger::OnClickBuffer, this);
|
||||
p_buffer_tex->Bind(wxEVT_LEFT_DOWN, &RSXDebugger::OnClickBuffer, this);
|
||||
m_list_captured_draw_calls->Bind(wxEVT_LEFT_DOWN, &RSXDebugger::OnClickDrawCalls, this);
|
||||
|
||||
@@ -364,6 +364,8 @@ void RSXDebugger::OnClickBuffer(wxMouseEvent& event)
|
||||
if (event.GetId() == p_buffer_colorB->GetId()) display_buffer(this, buffer_img[1]);
|
||||
if (event.GetId() == p_buffer_colorC->GetId()) display_buffer(this, buffer_img[2]);
|
||||
if (event.GetId() == p_buffer_colorD->GetId()) display_buffer(this, buffer_img[3]);
|
||||
if (event.GetId() == p_buffer_depth->GetId()) display_buffer(this, depth_img);
|
||||
if (event.GetId() == p_buffer_stencil->GetId()) display_buffer(this, stencil_img);
|
||||
if (event.GetId() == p_buffer_tex->GetId())
|
||||
{
|
||||
u8 location = render.textures[m_cur_texture].location();
|
||||
@@ -380,18 +382,74 @@ void RSXDebugger::OnClickBuffer(wxMouseEvent& event)
|
||||
|
||||
namespace
|
||||
{
|
||||
std::array<u8, 3> get_value(gsl::span<const gsl::byte> orig_buffer, rsx::surface_color_format format, size_t idx)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case rsx::surface_color_format::b8:
|
||||
{
|
||||
u8 value = gsl::as_span<const u8>(orig_buffer)[idx];
|
||||
return{ value, value, value };
|
||||
}
|
||||
case rsx::surface_color_format::x32:
|
||||
{
|
||||
be_t<u32> stored_val = gsl::as_span<const be_t<u32>>(orig_buffer)[idx];
|
||||
u32 swapped_val = stored_val;
|
||||
f32 float_val = (f32&)swapped_val;
|
||||
u8 val = float_val * 255.f;
|
||||
return{ val, val, val };
|
||||
}
|
||||
case rsx::surface_color_format::a8b8g8r8:
|
||||
case rsx::surface_color_format::x8b8g8r8_o8b8g8r8:
|
||||
case rsx::surface_color_format::x8b8g8r8_z8b8g8r8:
|
||||
{
|
||||
auto ptr = gsl::as_span<const u8>(orig_buffer);
|
||||
return{ ptr[1 + idx * 4], ptr[2 + idx * 4], ptr[3 + idx * 4] };
|
||||
}
|
||||
case rsx::surface_color_format::a8r8g8b8:
|
||||
case rsx::surface_color_format::x8r8g8b8_o8r8g8b8:
|
||||
case rsx::surface_color_format::x8r8g8b8_z8r8g8b8:
|
||||
{
|
||||
auto ptr = gsl::as_span<const u8>(orig_buffer);
|
||||
return{ ptr[3 + idx * 4], ptr[2 + idx * 4], ptr[1 + idx * 4] };
|
||||
}
|
||||
case rsx::surface_color_format::w16z16y16x16:
|
||||
{
|
||||
auto ptr = gsl::as_span<const u16>(orig_buffer);
|
||||
f16 h0 = f16(ptr[4 * idx]);
|
||||
f16 h1 = f16(ptr[4 * idx + 1]);
|
||||
f16 h2 = f16(ptr[4 * idx + 2]);
|
||||
f32 f0 = float(h0);
|
||||
f32 f1 = float(h1);
|
||||
f32 f2 = float(h2);
|
||||
|
||||
u8 val0 = f0 * 255.;
|
||||
u8 val1 = f1 * 255.;
|
||||
u8 val2 = f2 * 255.;
|
||||
return{ val0, val1, val2 };
|
||||
}
|
||||
case rsx::surface_color_format::g8b8:
|
||||
case rsx::surface_color_format::r5g6b5:
|
||||
case rsx::surface_color_format::x1r5g5b5_o1r5g5b5:
|
||||
case rsx::surface_color_format::x1r5g5b5_z1r5g5b5:
|
||||
case rsx::surface_color_format::w32z32y32x32:
|
||||
throw EXCEPTION("Unsupported format for display");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new buffer that can be passed to wxImage ctor.
|
||||
* The pointer seems to be freed by wxImage.
|
||||
*/
|
||||
u8* convert_to_wximage_buffer(u8 *orig_buffer, size_t width, size_t height) noexcept
|
||||
u8* convert_to_wximage_buffer(rsx::surface_color_format format, gsl::span<const gsl::byte> orig_buffer, size_t width, size_t height) noexcept
|
||||
{
|
||||
unsigned char* buffer = (unsigned char*)malloc(width * height * 3);
|
||||
for (u32 i = 0; i < width * height; i++)
|
||||
{
|
||||
buffer[0 + i * 3] = orig_buffer[3 + i * 4];
|
||||
buffer[1 + i * 3] = orig_buffer[2 + i * 4];
|
||||
buffer[2 + i * 3] = orig_buffer[1 + i * 4];
|
||||
const auto &colors = get_value(orig_buffer, format, i);
|
||||
buffer[0 + i * 3] = colors[0];
|
||||
buffer[1 + i * 3] = colors[1];
|
||||
buffer[2 + i * 3] = colors[2];
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
@@ -401,6 +459,8 @@ void RSXDebugger::OnClickDrawCalls(wxMouseEvent& event)
|
||||
{
|
||||
size_t draw_id = m_list_captured_draw_calls->GetFirstSelected();
|
||||
|
||||
const auto& draw_call = frame_debug.draw_calls[draw_id];
|
||||
|
||||
wxPanel* p_buffers[] =
|
||||
{
|
||||
p_buffer_colorA,
|
||||
@@ -409,13 +469,14 @@ void RSXDebugger::OnClickDrawCalls(wxMouseEvent& event)
|
||||
p_buffer_colorD,
|
||||
};
|
||||
|
||||
size_t width = draw_call.width;
|
||||
size_t height = draw_call.height;
|
||||
|
||||
for (size_t i = 0; i < 4; i++)
|
||||
{
|
||||
size_t width = frame_debug.draw_calls[draw_id].color_buffer[i].width, height = frame_debug.draw_calls[draw_id].color_buffer[i].height;
|
||||
if (width && height)
|
||||
if (width && height && !draw_call.color_buffer[i].empty())
|
||||
{
|
||||
unsigned char *orig_buffer = frame_debug.draw_calls[draw_id].color_buffer[i].data.data();
|
||||
buffer_img[i] = wxImage(width, height, convert_to_wximage_buffer(orig_buffer, width, height));
|
||||
buffer_img[i] = wxImage(width, height, convert_to_wximage_buffer(draw_call.color_format, draw_call.color_buffer[i], width, height));
|
||||
wxClientDC dc_canvas(p_buffers[i]);
|
||||
|
||||
if (buffer_img[i].IsOk())
|
||||
@@ -425,56 +486,71 @@ void RSXDebugger::OnClickDrawCalls(wxMouseEvent& event)
|
||||
|
||||
// Buffer Z
|
||||
{
|
||||
size_t width = frame_debug.draw_calls[draw_id].depth.width, height = frame_debug.draw_calls[draw_id].depth.height;
|
||||
if (width && height)
|
||||
if (width && height && !draw_call.depth_stencil[0].empty())
|
||||
{
|
||||
u32 *orig_buffer = (u32*)frame_debug.draw_calls[draw_id].depth.data.data();
|
||||
gsl::span<const gsl::byte> orig_buffer = draw_call.depth_stencil[0];
|
||||
unsigned char *buffer = (unsigned char *)malloc(width * height * 3);
|
||||
|
||||
for (u32 row = 0; row < height; row++)
|
||||
if (draw_call.depth_format == rsx::surface_depth_format::z24s8)
|
||||
{
|
||||
for (u32 col = 0; col < width; col++)
|
||||
for (u32 row = 0; row < height; row++)
|
||||
{
|
||||
u32 depth_val = orig_buffer[row * width + col];
|
||||
u8 displayed_depth_val = 255 * depth_val / 0xFFFFFF;
|
||||
buffer[3 * col + 0 + width * row * 3] = displayed_depth_val;
|
||||
buffer[3 * col + 1 + width * row * 3] = displayed_depth_val;
|
||||
buffer[3 * col + 2 + width * row * 3] = displayed_depth_val;
|
||||
for (u32 col = 0; col < width; col++)
|
||||
{
|
||||
u32 depth_val = gsl::as_span<const u32>(orig_buffer)[row * width + col];
|
||||
u8 displayed_depth_val = 255 * depth_val / 0xFFFFFF;
|
||||
buffer[3 * col + 0 + width * row * 3] = displayed_depth_val;
|
||||
buffer[3 * col + 1 + width * row * 3] = displayed_depth_val;
|
||||
buffer[3 * col + 2 + width * row * 3] = displayed_depth_val;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (u32 row = 0; row < height; row++)
|
||||
{
|
||||
for (u32 col = 0; col < width; col++)
|
||||
{
|
||||
u16 depth_val = gsl::as_span<const u16>(orig_buffer)[row * width + col];
|
||||
u8 displayed_depth_val = 255 * depth_val / 0xFFFF;
|
||||
buffer[3 * col + 0 + width * row * 3] = displayed_depth_val;
|
||||
buffer[3 * col + 1 + width * row * 3] = displayed_depth_val;
|
||||
buffer[3 * col + 2 + width * row * 3] = displayed_depth_val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wxImage img(width, height, buffer);
|
||||
depth_img = wxImage(width, height, buffer);
|
||||
wxClientDC dc_canvas(p_buffer_depth);
|
||||
|
||||
if (img.IsOk())
|
||||
dc_canvas.DrawBitmap(img.Scale(m_panel_width, m_panel_height), 0, 0, false);
|
||||
if (depth_img.IsOk())
|
||||
dc_canvas.DrawBitmap(depth_img.Scale(m_panel_width, m_panel_height), 0, 0, false);
|
||||
}
|
||||
}
|
||||
|
||||
// Buffer S
|
||||
{
|
||||
size_t width = frame_debug.draw_calls[draw_id].stencil.width, height = frame_debug.draw_calls[draw_id].stencil.height;
|
||||
if (width && height)
|
||||
if (width && height && !draw_call.depth_stencil[1].empty())
|
||||
{
|
||||
u8 *orig_buffer = frame_debug.draw_calls[draw_id].stencil.data.data();
|
||||
gsl::span<const gsl::byte> orig_buffer = draw_call.depth_stencil[1];
|
||||
unsigned char *buffer = (unsigned char *)malloc(width * height * 3);
|
||||
|
||||
for (u32 row = 0; row < height; row++)
|
||||
{
|
||||
for (u32 col = 0; col < width; col++)
|
||||
{
|
||||
u32 stencil_val = orig_buffer[row * width + col];
|
||||
u8 stencil_val = gsl::as_span<const u8>(orig_buffer)[row * width + col];
|
||||
buffer[3 * col + 0 + width * row * 3] = stencil_val;
|
||||
buffer[3 * col + 1 + width * row * 3] = stencil_val;
|
||||
buffer[3 * col + 2 + width * row * 3] = stencil_val;
|
||||
}
|
||||
}
|
||||
|
||||
wxImage img(width, height, buffer);
|
||||
stencil_img = wxImage(width, height, buffer);
|
||||
wxClientDC dc_canvas(p_buffer_stencil);
|
||||
|
||||
if (img.IsOk())
|
||||
dc_canvas.DrawBitmap(img.Scale(m_panel_width, m_panel_height), 0, 0, false);
|
||||
if (stencil_img.IsOk())
|
||||
dc_canvas.DrawBitmap(stencil_img.Scale(m_panel_width, m_panel_height), 0, 0, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -764,11 +840,11 @@ void RSXDebugger::GetSettings()
|
||||
render.m_color_mask_g,
|
||||
render.m_color_mask_b,
|
||||
render.m_color_mask_a));
|
||||
LIST_SETTINGS_ADD("Context DMA Color A", wxString::Format("0x%x", render.m_context_dma_color_a));
|
||||
LIST_SETTINGS_ADD("Context DMA Color B", wxString::Format("0x%x", render.m_context_dma_color_b));
|
||||
LIST_SETTINGS_ADD("Context DMA Color C", wxString::Format("0x%x", render.m_context_dma_color_c));
|
||||
LIST_SETTINGS_ADD("Context DMA Color D", wxString::Format("0x%x", render.m_context_dma_color_d));
|
||||
LIST_SETTINGS_ADD("Context DMA Zeta", wxString::Format("0x%x", render.m_context_dma_z));
|
||||
LIST_SETTINGS_ADD("Context DMA color A", wxString::Format("0x%x", render.m_context_dma_color_a));
|
||||
LIST_SETTINGS_ADD("Context DMA color B", wxString::Format("0x%x", render.m_context_dma_color_b));
|
||||
LIST_SETTINGS_ADD("Context DMA color C", wxString::Format("0x%x", render.m_context_dma_color_c));
|
||||
LIST_SETTINGS_ADD("Context DMA color D", wxString::Format("0x%x", render.m_context_dma_color_d));
|
||||
LIST_SETTINGS_ADD("Context DMA zeta", wxString::Format("0x%x", render.m_context_dma_z));
|
||||
LIST_SETTINGS_ADD("Depth bounds", wxString::Format("Min:%f, Max:%f", render.m_depth_bounds_min, render.m_depth_bounds_max));
|
||||
LIST_SETTINGS_ADD("Depth func", !(render.m_set_depth_func) ? "(none)" : wxString::Format("0x%x (%s)",
|
||||
render.m_depth_func,
|
||||
@@ -784,16 +860,16 @@ void RSXDebugger::GetSettings()
|
||||
LIST_SETTINGS_ADD("Stencil func", !(render.m_set_stencil_func) ? "(none)" : wxString::Format("0x%x (%s)",
|
||||
render.m_stencil_func,
|
||||
ParseGCMEnum(render.m_stencil_func, CELL_GCM_ENUM)));
|
||||
LIST_SETTINGS_ADD("Surface Pitch A", wxString::Format("0x%x", render.m_surface_pitch_a));
|
||||
LIST_SETTINGS_ADD("Surface Pitch B", wxString::Format("0x%x", render.m_surface_pitch_b));
|
||||
LIST_SETTINGS_ADD("Surface Pitch C", wxString::Format("0x%x", render.m_surface_pitch_c));
|
||||
LIST_SETTINGS_ADD("Surface Pitch D", wxString::Format("0x%x", render.m_surface_pitch_d));
|
||||
LIST_SETTINGS_ADD("Surface Pitch Z", wxString::Format("0x%x", render.m_surface_pitch_z));
|
||||
LIST_SETTINGS_ADD("Surface Offset A", wxString::Format("0x%x", render.m_surface_offset_a));
|
||||
LIST_SETTINGS_ADD("Surface Offset B", wxString::Format("0x%x", render.m_surface_offset_b));
|
||||
LIST_SETTINGS_ADD("Surface Offset C", wxString::Format("0x%x", render.m_surface_offset_c));
|
||||
LIST_SETTINGS_ADD("Surface Offset D", wxString::Format("0x%x", render.m_surface_offset_d));
|
||||
LIST_SETTINGS_ADD("Surface Offset Z", wxString::Format("0x%x", render.m_surface_offset_z));
|
||||
LIST_SETTINGS_ADD("Surface pitch A", wxString::Format("0x%x", render.m_surface_pitch_a));
|
||||
LIST_SETTINGS_ADD("Surface pitch B", wxString::Format("0x%x", render.m_surface_pitch_b));
|
||||
LIST_SETTINGS_ADD("Surface pitch C", wxString::Format("0x%x", render.m_surface_pitch_c));
|
||||
LIST_SETTINGS_ADD("Surface pitch D", wxString::Format("0x%x", render.m_surface_pitch_d));
|
||||
LIST_SETTINGS_ADD("Surface pitch Z", wxString::Format("0x%x", render.m_surface_pitch_z));
|
||||
LIST_SETTINGS_ADD("Surface offset A", wxString::Format("0x%x", render.m_surface_offset_a));
|
||||
LIST_SETTINGS_ADD("Surface offset B", wxString::Format("0x%x", render.m_surface_offset_b));
|
||||
LIST_SETTINGS_ADD("Surface offset C", wxString::Format("0x%x", render.m_surface_offset_c));
|
||||
LIST_SETTINGS_ADD("Surface offset D", wxString::Format("0x%x", render.m_surface_offset_d));
|
||||
LIST_SETTINGS_ADD("Surface offset Z", wxString::Format("0x%x", render.m_surface_offset_z));
|
||||
LIST_SETTINGS_ADD("Viewport", wxString::Format("X:%d, Y:%d, W:%d, H:%d",
|
||||
render.m_viewport_x,
|
||||
render.m_viewport_y,
|
||||
@@ -846,8 +922,8 @@ void RSXDebugger::SetPrograms(wxListEvent& event)
|
||||
wxDEFAULT_DIALOG_STYLE | wxMINIMIZE_BOX | wxMAXIMIZE_BOX | wxRESIZE_BORDER);
|
||||
|
||||
wxBoxSizer& s_panel = *new wxBoxSizer(wxHORIZONTAL);
|
||||
wxStaticBoxSizer& s_vp_box = *new wxStaticBoxSizer(wxHORIZONTAL, &d_editor, "Vertex Program");
|
||||
wxStaticBoxSizer& s_fp_box = *new wxStaticBoxSizer(wxHORIZONTAL, &d_editor, "Fragment Program");
|
||||
wxStaticBoxSizer& s_vp_box = *new wxStaticBoxSizer(wxHORIZONTAL, &d_editor, "Vertex program");
|
||||
wxStaticBoxSizer& s_fp_box = *new wxStaticBoxSizer(wxHORIZONTAL, &d_editor, "Fragment program");
|
||||
wxTextCtrl* t_vp_edit = new wxTextCtrl(&d_editor, wxID_ANY, program.vp_shader, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE);
|
||||
wxTextCtrl* t_fp_edit = new wxTextCtrl(&d_editor, wxID_ANY, program.fp_shader, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE);
|
||||
t_vp_edit->SetFont(wxFont(8, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL));
|
||||
@@ -891,10 +967,10 @@ const char* RSXDebugger::ParseGCMEnum(u32 value, u32 type)
|
||||
case 0x0200: return "Never";
|
||||
case 0x0201: return "Less";
|
||||
case 0x0202: return "Equal";
|
||||
case 0x0203: return "Less or Equal";
|
||||
case 0x0203: return "Less or equal";
|
||||
case 0x0204: return "Greater";
|
||||
case 0x0205: return "Not Equal";
|
||||
case 0x0206: return "Greater or Equal";
|
||||
case 0x0205: return "Not equal";
|
||||
case 0x0206: return "Greater or equal";
|
||||
case 0x0207: return "Always";
|
||||
|
||||
case 0x0: return "Zero";
|
||||
@@ -917,12 +993,12 @@ const char* RSXDebugger::ParseGCMEnum(u32 value, u32 type)
|
||||
case 0x8007: return "Min";
|
||||
case 0x8008: return "Max";
|
||||
case 0x800A: return "Substract";
|
||||
case 0x800B: return "Reverse Substract";
|
||||
case 0xF005: return "Reverse Substract Signed";
|
||||
case 0xF006: return "Add Signed";
|
||||
case 0xF007: return "Reverse Add Signed";
|
||||
case 0x800B: return "Reverse substract";
|
||||
case 0xF005: return "Reverse substract signed";
|
||||
case 0xF006: return "Add signed";
|
||||
case 0xF007: return "Reverse add signed";
|
||||
|
||||
default: return "Wrong Value!";
|
||||
default: return "Wrong value!";
|
||||
}
|
||||
}
|
||||
case CELL_GCM_PRIMITIVE_ENUM:
|
||||
@@ -940,7 +1016,7 @@ const char* RSXDebugger::ParseGCMEnum(u32 value, u32 type)
|
||||
case 9: return "QUAD_STRIP";
|
||||
case 10: return "POLYGON";
|
||||
|
||||
default: return "Wrong Value!";
|
||||
default: return "Wrong value!";
|
||||
}
|
||||
}
|
||||
default: return "Unknown!";
|
||||
@@ -1002,7 +1078,7 @@ wxString RSXDebugger::DisAsmCommand(u32 cmd, u32 count, u32 currentAddr, u32 ioA
|
||||
break;
|
||||
|
||||
case_16(NV4097_SET_TEXTURE_OFFSET, 0x20):
|
||||
DISASM("Texture Offset[%d]: %08x", index, (u32)args[0]);
|
||||
DISASM("Texture offset[%d]: %08x", index, (u32)args[0]);
|
||||
switch ((args[1] & 0x3) - 1)
|
||||
{
|
||||
case CELL_GCM_LOCATION_LOCAL: DISASM("(Local memory);"); break;
|
||||
|
||||
@@ -29,6 +29,8 @@ class RSXDebugger : public wxDialog
|
||||
wxPanel* p_buffer_tex;
|
||||
|
||||
wxImage buffer_img[4];
|
||||
wxImage depth_img;
|
||||
wxImage stencil_img;
|
||||
|
||||
wxTextCtrl* m_text_transform_program;
|
||||
wxTextCtrl *m_text_shader_program;
|
||||
|
||||
@@ -134,24 +134,24 @@ SettingsDialog::SettingsDialog(wxWindow *parent, rpcs3::config_t* cfg)
|
||||
wxStaticBoxSizer* s_round_llvm_threshold = new wxStaticBoxSizer(wxHORIZONTAL, p_core, _("Compilation threshold"));
|
||||
|
||||
// Graphics
|
||||
wxStaticBoxSizer* s_round_gs_render = new wxStaticBoxSizer(wxVERTICAL, p_graphics, _("Render"));
|
||||
wxStaticBoxSizer* s_round_gs_d3d_adaptater = new wxStaticBoxSizer(wxVERTICAL, p_graphics, _("D3D Adaptater"));
|
||||
wxStaticBoxSizer* s_round_gs_render = new wxStaticBoxSizer(wxVERTICAL, p_graphics, _("Rendering API"));
|
||||
wxStaticBoxSizer* s_round_gs_d3d_adaptater = new wxStaticBoxSizer(wxVERTICAL, p_graphics, _("D3D Adapter"));
|
||||
wxStaticBoxSizer* s_round_gs_res = new wxStaticBoxSizer(wxVERTICAL, p_graphics, _("Resolution"));
|
||||
wxStaticBoxSizer* s_round_gs_aspect = new wxStaticBoxSizer(wxVERTICAL, p_graphics, _("Aspect ratio"));
|
||||
wxStaticBoxSizer* s_round_gs_frame_limit = new wxStaticBoxSizer(wxVERTICAL, p_graphics, _("Frame limit"));
|
||||
|
||||
// Input / Output
|
||||
wxStaticBoxSizer* s_round_io_pad_handler = new wxStaticBoxSizer(wxVERTICAL, p_io, _("Pad Handler"));
|
||||
wxStaticBoxSizer* s_round_io_keyboard_handler = new wxStaticBoxSizer(wxVERTICAL, p_io, _("Keyboard Handler"));
|
||||
wxStaticBoxSizer* s_round_io_mouse_handler = new wxStaticBoxSizer(wxVERTICAL, p_io, _("Mouse Handler"));
|
||||
wxStaticBoxSizer* s_round_io_pad_handler = new wxStaticBoxSizer(wxVERTICAL, p_io, _("Controller handler"));
|
||||
wxStaticBoxSizer* s_round_io_keyboard_handler = new wxStaticBoxSizer(wxVERTICAL, p_io, _("Keyboard handler"));
|
||||
wxStaticBoxSizer* s_round_io_mouse_handler = new wxStaticBoxSizer(wxVERTICAL, p_io, _("Mouse handler"));
|
||||
wxStaticBoxSizer* s_round_io_camera = new wxStaticBoxSizer(wxVERTICAL, p_io, _("Camera"));
|
||||
wxStaticBoxSizer* s_round_io_camera_type = new wxStaticBoxSizer(wxVERTICAL, p_io, _("Camera type"));
|
||||
|
||||
// Audio
|
||||
wxStaticBoxSizer* s_round_audio_out = new wxStaticBoxSizer(wxVERTICAL, p_audio, _("Audio Out"));
|
||||
wxStaticBoxSizer* s_round_audio_out = new wxStaticBoxSizer(wxVERTICAL, p_audio, _("Audio out"));
|
||||
|
||||
// Miscellaneous
|
||||
wxStaticBoxSizer* s_round_hle_log_lvl = new wxStaticBoxSizer(wxVERTICAL, p_misc, _("Log Level"));
|
||||
wxStaticBoxSizer* s_round_hle_log_lvl = new wxStaticBoxSizer(wxVERTICAL, p_misc, _("Log level"));
|
||||
|
||||
// Networking
|
||||
wxStaticBoxSizer* s_round_net_status = new wxStaticBoxSizer(wxVERTICAL, p_networking, _("Connection status"));
|
||||
@@ -183,17 +183,17 @@ SettingsDialog::SettingsDialog(wxWindow *parent, rpcs3::config_t* cfg)
|
||||
wxCheckBox* chbox_core_hook_stfunc = new wxCheckBox(p_core, wxID_ANY, "Hook static functions");
|
||||
wxCheckBox* chbox_core_load_liblv2 = new wxCheckBox(p_core, wxID_ANY, "Load liblv2.sprx");
|
||||
wxCheckBox* chbox_gs_log_prog = new wxCheckBox(p_graphics, wxID_ANY, "Log shader programs");
|
||||
wxCheckBox* chbox_gs_dump_depth = new wxCheckBox(p_graphics, wxID_ANY, "Write Depth Buffer");
|
||||
wxCheckBox* chbox_gs_dump_color = new wxCheckBox(p_graphics, wxID_ANY, "Write Color Buffers");
|
||||
wxCheckBox* chbox_gs_read_color = new wxCheckBox(p_graphics, wxID_ANY, "Read Color Buffers");
|
||||
wxCheckBox* chbox_gs_read_depth = new wxCheckBox(p_graphics, wxID_ANY, "Read Depth Buffer");
|
||||
wxCheckBox* chbox_gs_dump_depth = new wxCheckBox(p_graphics, wxID_ANY, "Write depth buffer");
|
||||
wxCheckBox* chbox_gs_dump_color = new wxCheckBox(p_graphics, wxID_ANY, "Write color buffers");
|
||||
wxCheckBox* chbox_gs_read_color = new wxCheckBox(p_graphics, wxID_ANY, "Read color buffers");
|
||||
wxCheckBox* chbox_gs_read_depth = new wxCheckBox(p_graphics, wxID_ANY, "Read depth buffer");
|
||||
wxCheckBox* chbox_gs_vsync = new wxCheckBox(p_graphics, wxID_ANY, "VSync");
|
||||
wxCheckBox* chbox_gs_debug_output = new wxCheckBox(p_graphics, wxID_ANY, "Debug Output");
|
||||
wxCheckBox* chbox_gs_3dmonitor = new wxCheckBox(p_graphics, wxID_ANY, "3D Monitor");
|
||||
wxCheckBox* chbox_gs_debug_output = new wxCheckBox(p_graphics, wxID_ANY, "Debug output");
|
||||
wxCheckBox* chbox_gs_3dmonitor = new wxCheckBox(p_graphics, wxID_ANY, "3D monitor");
|
||||
wxCheckBox* chbox_gs_overlay = new wxCheckBox(p_graphics, wxID_ANY, "Debug overlay");
|
||||
wxCheckBox* chbox_audio_dump = new wxCheckBox(p_audio, wxID_ANY, "Dump to file");
|
||||
wxCheckBox* chbox_audio_conv = new wxCheckBox(p_audio, wxID_ANY, "Convert to 16 bit");
|
||||
wxCheckBox* chbox_rsx_logging = new wxCheckBox(p_misc, wxID_ANY, "RSX Logging");
|
||||
wxCheckBox* chbox_audio_conv = new wxCheckBox(p_audio, wxID_ANY, "Convert to 16-bit");
|
||||
wxCheckBox* chbox_rsx_logging = new wxCheckBox(p_misc, wxID_ANY, "RSX logging");
|
||||
wxCheckBox* chbox_hle_exitonstop = new wxCheckBox(p_misc, wxID_ANY, "Exit RPCS3 when process finishes");
|
||||
wxCheckBox* chbox_hle_always_start = new wxCheckBox(p_misc, wxID_ANY, "Always start after boot");
|
||||
wxCheckBox* chbox_hle_use_default_ini = new wxCheckBox(p_misc, wxID_ANY, "Use default configuration");
|
||||
@@ -203,8 +203,8 @@ SettingsDialog::SettingsDialog(wxWindow *parent, rpcs3::config_t* cfg)
|
||||
wxTextCtrl* txt_llvm_threshold = new wxTextCtrl(p_core, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(55, 20));
|
||||
|
||||
//Auto Pause
|
||||
wxCheckBox* chbox_dbg_ap_systemcall = new wxCheckBox(p_misc, wxID_ANY, "Auto Pause at System Call");
|
||||
wxCheckBox* chbox_dbg_ap_functioncall = new wxCheckBox(p_misc, wxID_ANY, "Auto Pause at Function Call");
|
||||
wxCheckBox* chbox_dbg_ap_systemcall = new wxCheckBox(p_misc, wxID_ANY, "Automatically pause at system call");
|
||||
wxCheckBox* chbox_dbg_ap_functioncall = new wxCheckBox(p_misc, wxID_ANY, "Automatically pause at function call");
|
||||
|
||||
//Custom EmulationDir
|
||||
wxCheckBox* chbox_emulationdir_enable = new wxCheckBox(p_system, wxID_ANY, "Use path below as EmulationDir. (Restart required)");
|
||||
@@ -215,7 +215,7 @@ SettingsDialog::SettingsDialog(wxWindow *parent, rpcs3::config_t* cfg)
|
||||
ppu_decoder_modes.Add("Interpreter");
|
||||
ppu_decoder_modes.Add("Interpreter 2");
|
||||
ppu_decoder_modes.Add("Recompiler (LLVM)");
|
||||
rbox_ppu_decoder = new wxRadioBox(p_core, wxID_ANY, "PPU Decoder", wxDefaultPosition, wxSize(215, -1), ppu_decoder_modes, 1);
|
||||
rbox_ppu_decoder = new wxRadioBox(p_core, wxID_ANY, "PPU decoder", wxDefaultPosition, wxSize(215, -1), ppu_decoder_modes, 1);
|
||||
|
||||
#if !defined(LLVM_AVAILABLE)
|
||||
rbox_ppu_decoder->Enable(2, false);
|
||||
@@ -225,7 +225,7 @@ SettingsDialog::SettingsDialog(wxWindow *parent, rpcs3::config_t* cfg)
|
||||
spu_decoder_modes.Add("Interpreter (precise)");
|
||||
spu_decoder_modes.Add("Interpreter (fast)");
|
||||
spu_decoder_modes.Add("Recompiler (ASMJIT)");
|
||||
rbox_spu_decoder = new wxRadioBox(p_core, wxID_ANY, "SPU Decoder", wxDefaultPosition, wxSize(215, -1), spu_decoder_modes, 1);
|
||||
rbox_spu_decoder = new wxRadioBox(p_core, wxID_ANY, "SPU decoder", wxDefaultPosition, wxSize(215, -1), spu_decoder_modes, 1);
|
||||
|
||||
cbox_gs_render->Append("Null");
|
||||
cbox_gs_render->Append("OpenGL");
|
||||
@@ -260,7 +260,7 @@ SettingsDialog::SettingsDialog(wxWindow *parent, rpcs3::config_t* cfg)
|
||||
cbox_gs_aspect->Append("4:3");
|
||||
cbox_gs_aspect->Append("16:9");
|
||||
|
||||
for (auto item : { "Off", "50", "59.94", "30", "60", "Auto" })
|
||||
for (auto item : { "Off", "30", "50", "59.94", "60", "Auto" })
|
||||
cbox_gs_frame_limit->Append(item);
|
||||
|
||||
cbox_pad_handler->Append("Null");
|
||||
|
||||
@@ -116,7 +116,7 @@ enum
|
||||
};
|
||||
|
||||
VFSManagerDialog::VFSManagerDialog(wxWindow* parent)
|
||||
: wxDialog(parent, wxID_ANY, "Virtual File System Manager")
|
||||
: wxDialog(parent, wxID_ANY, "Virtual file system manager")
|
||||
{
|
||||
m_list = new wxListView(this);
|
||||
|
||||
@@ -134,7 +134,7 @@ VFSManagerDialog::VFSManagerDialog(wxWindow* parent)
|
||||
|
||||
m_list->InsertColumn(0, "Path");
|
||||
m_list->InsertColumn(1, "Device path");
|
||||
m_list->InsertColumn(2, "Path to Device");
|
||||
m_list->InsertColumn(2, "Path to device");
|
||||
m_list->InsertColumn(3, "Device");
|
||||
|
||||
m_list->Bind(wxEVT_LIST_ITEM_ACTIVATED, &VFSManagerDialog::OnEntryConfig, this);
|
||||
|
||||
@@ -50,7 +50,7 @@ enum
|
||||
id_add_hdd
|
||||
};
|
||||
|
||||
VHDDExplorer::VHDDExplorer(wxWindow* parent, const std::string& hdd_path) : wxDialog(parent, wxID_ANY, "Virtual HDD Explorer", wxDefaultPosition)
|
||||
VHDDExplorer::VHDDExplorer(wxWindow* parent, const std::string& hdd_path) : wxDialog(parent, wxID_ANY, "Virtual hard drive explorer", wxDefaultPosition)
|
||||
{
|
||||
m_list = new wxListView(this);
|
||||
m_drop_target = new VHDDListDropTarget(m_list);
|
||||
@@ -249,18 +249,18 @@ void VHDDExplorer::OnRemove(wxCommandEvent& event)
|
||||
void VHDDExplorer::OnCreateDir(wxCommandEvent& event)
|
||||
{
|
||||
int i = 1;
|
||||
while(m_hdd->HasEntry(fmt::format("New Dir (%d)", i))) i++;
|
||||
while(m_hdd->HasEntry(fmt::format("New dir (%d)", i))) i++;
|
||||
|
||||
m_hdd->Create(vfsHDD_Entry_Dir, fmt::format("New Dir (%d)", i));
|
||||
m_hdd->Create(vfsHDD_Entry_Dir, fmt::format("New dir (%d)", i));
|
||||
UpdateList();
|
||||
}
|
||||
|
||||
void VHDDExplorer::OnCreateFile(wxCommandEvent& event)
|
||||
{
|
||||
int i = 1;
|
||||
while (m_hdd->HasEntry(fmt::format("New File (%d)", i))) i++;
|
||||
while (m_hdd->HasEntry(fmt::format("New file (%d)", i))) i++;
|
||||
|
||||
m_hdd->Create(vfsHDD_Entry_File, fmt::format("New File (%d)", i));
|
||||
m_hdd->Create(vfsHDD_Entry_File, fmt::format("New file (%d)", i));
|
||||
UpdateList();
|
||||
}
|
||||
|
||||
@@ -376,7 +376,7 @@ void VHDDSetInfoDialog::GetResult(u64& size, u64& block_size)
|
||||
}
|
||||
|
||||
VHDDManagerDialog::VHDDManagerDialog(wxWindow* parent)
|
||||
: wxDialog(parent, wxID_ANY, "Virtual HDD Manager")
|
||||
: wxDialog(parent, wxID_ANY, "Virtual hard drive Manager")
|
||||
{
|
||||
m_list = new wxListView(this);
|
||||
|
||||
@@ -438,7 +438,7 @@ void VHDDManagerDialog::DClick(wxListEvent& event)
|
||||
|
||||
void VHDDManagerDialog::AddHDD(wxCommandEvent& event)
|
||||
{
|
||||
wxFileDialog ctrl(this, "Select HDDs", wxEmptyString, wxEmptyString, "Virtual HDD (*.hdd) | *.hdd",
|
||||
wxFileDialog ctrl(this, "Select hard drives", wxEmptyString, wxEmptyString, "Virtual hard drive (*.hdd) | *.hdd",
|
||||
wxFD_OPEN | wxFD_FILE_MUST_EXIST | wxFD_MULTIPLE);
|
||||
|
||||
if(ctrl.ShowModal() == wxID_CANCEL)
|
||||
@@ -498,7 +498,7 @@ void VHDDManagerDialog::OnRemove(wxCommandEvent& event)
|
||||
|
||||
void VHDDManagerDialog::OnCreateHDD(wxCommandEvent& event)
|
||||
{
|
||||
wxFileDialog ctrl(this, "Select HDD path", wxEmptyString, "new_hdd.hdd", "Virtual HDD (*.hdd) | *.hdd",
|
||||
wxFileDialog ctrl(this, "Select hard drive path", wxEmptyString, "new_hdd.hdd", "Virtual hard drive (*.hdd) | *.hdd",
|
||||
wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
|
||||
|
||||
if(ctrl.ShowModal() == wxID_CANCEL)
|
||||
|
||||
+224
-267
@@ -1,300 +1,257 @@
|
||||
#include "stdafx.h"
|
||||
#include "Emu/FS/vfsStream.h"
|
||||
#include "PSF.h"
|
||||
|
||||
bool PSFLoader::Load(vfsStream& stream)
|
||||
namespace psf
|
||||
{
|
||||
PSFHeader header;
|
||||
_log::channel log("PSF");
|
||||
|
||||
// load header
|
||||
if (!stream.SRead(header))
|
||||
struct header_t
|
||||
{
|
||||
return false;
|
||||
le_t<u32> magic;
|
||||
le_t<u32> version;
|
||||
le_t<u32> off_key_table;
|
||||
le_t<u32> off_data_table;
|
||||
le_t<u32> entries_num;
|
||||
};
|
||||
|
||||
struct def_table_t
|
||||
{
|
||||
le_t<u16> key_off;
|
||||
le_t<format> param_fmt;
|
||||
le_t<u32> param_len;
|
||||
le_t<u32> param_max;
|
||||
le_t<u32> data_off;
|
||||
};
|
||||
|
||||
const std::string& entry::as_string() const
|
||||
{
|
||||
CHECK_ASSERTION(m_type == format::string || m_type == format::array);
|
||||
return m_value_string;
|
||||
}
|
||||
|
||||
// check magic
|
||||
if (header.magic != *(u32*)"\0PSF")
|
||||
u32 entry::as_integer() const
|
||||
{
|
||||
LOG_ERROR(LOADER, "PSFLoader::Load() failed: unknown magic (0x%x)", header.magic);
|
||||
return false;
|
||||
CHECK_ASSERTION(m_type == format::integer);
|
||||
return m_value_integer;
|
||||
}
|
||||
|
||||
// check version
|
||||
if (header.version != 0x101)
|
||||
entry& entry::operator =(const std::string& value)
|
||||
{
|
||||
LOG_ERROR(LOADER, "PSFLoader::Load() failed: unknown version (0x%x)", header.version);
|
||||
return false;
|
||||
CHECK_ASSERTION(m_type == format::string || m_type == format::array);
|
||||
m_value_string = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// load indices
|
||||
std::vector<PSFDefTable> indices;
|
||||
|
||||
indices.resize(header.entries_num);
|
||||
|
||||
if (!stream.SRead(indices[0], sizeof(PSFDefTable) * header.entries_num))
|
||||
entry& entry::operator =(u32 value)
|
||||
{
|
||||
return false;
|
||||
CHECK_ASSERTION(m_type == format::integer);
|
||||
m_value_integer = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// load key table
|
||||
if (header.off_key_table > header.off_data_table)
|
||||
u32 entry::size() const
|
||||
{
|
||||
LOG_ERROR(LOADER, "PSFLoader::Load() failed: off_key_table=0x%x, off_data_table=0x%x", header.off_key_table, header.off_data_table);
|
||||
return false;
|
||||
}
|
||||
|
||||
const u32 key_table_size = header.off_data_table - header.off_key_table;
|
||||
|
||||
std::unique_ptr<char[]> keys(new char[key_table_size + 1]);
|
||||
|
||||
stream.Seek(header.off_key_table);
|
||||
|
||||
if (stream.Read(keys.get(), key_table_size) != key_table_size)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
keys.get()[key_table_size] = 0;
|
||||
|
||||
// load entries
|
||||
std::vector<PSFEntry> entries;
|
||||
|
||||
entries.resize(header.entries_num);
|
||||
|
||||
for (u32 i = 0; i < header.entries_num; ++i)
|
||||
{
|
||||
entries[i].fmt = indices[i].param_fmt;
|
||||
|
||||
if (indices[i].key_off >= key_table_size)
|
||||
switch (m_type)
|
||||
{
|
||||
return false;
|
||||
case format::string:
|
||||
case format::array:
|
||||
return std::min(m_max_size, gsl::narrow<u32>(m_value_string.size() + (m_type == format::string)));
|
||||
|
||||
case format::integer:
|
||||
return SIZE_32(u32);
|
||||
}
|
||||
|
||||
entries[i].name = keys.get() + indices[i].key_off;
|
||||
throw EXCEPTION("Invalid format (0x%x)", m_type);
|
||||
}
|
||||
|
||||
// load data
|
||||
stream.Seek(header.off_data_table + indices[i].data_off);
|
||||
registry load(const std::vector<char>& data)
|
||||
{
|
||||
registry result;
|
||||
|
||||
if (indices[i].param_fmt == psf_entry_format::integer && indices[i].param_len == 4 && indices[i].param_max >= indices[i].param_len)
|
||||
// Hack for empty input (TODO)
|
||||
if (data.empty())
|
||||
{
|
||||
// load int data
|
||||
return result;
|
||||
}
|
||||
|
||||
if (!stream.SRead(entries[i].vint))
|
||||
// Check size
|
||||
CHECK_ASSERTION(data.size() >= sizeof(header_t));
|
||||
CHECK_ASSERTION((std::uintptr_t)data.data() % 8 == 0);
|
||||
|
||||
// Get header
|
||||
const header_t& header = reinterpret_cast<const header_t&>(data[0]);
|
||||
|
||||
// Check magic and version
|
||||
CHECK_ASSERTION(header.magic == *(u32*)"\0PSF");
|
||||
CHECK_ASSERTION(header.version == 0x101);
|
||||
CHECK_ASSERTION(sizeof(header_t) + header.entries_num * sizeof(def_table_t) <= header.off_key_table);
|
||||
CHECK_ASSERTION(header.off_key_table <= header.off_data_table);
|
||||
CHECK_ASSERTION(header.off_data_table <= data.size());
|
||||
|
||||
// Get indices (alignment should be fine)
|
||||
const def_table_t* indices = reinterpret_cast<const def_table_t*>(data.data() + sizeof(header_t));
|
||||
|
||||
// Load entries
|
||||
for (u32 i = 0; i < header.entries_num; ++i)
|
||||
{
|
||||
CHECK_ASSERTION(indices[i].key_off < header.off_data_table - header.off_key_table);
|
||||
|
||||
// Get key name range
|
||||
const auto name_ptr = data.begin() + header.off_key_table + indices[i].key_off;
|
||||
const auto name_end = std::find(name_ptr , data.begin() + header.off_data_table, '\0');
|
||||
|
||||
// Get name (must be unique)
|
||||
std::string key(name_ptr, name_end);
|
||||
|
||||
CHECK_ASSERTION(result.count(key) == 0);
|
||||
CHECK_ASSERTION(indices[i].param_len <= indices[i].param_max);
|
||||
CHECK_ASSERTION(indices[i].data_off < data.size() - header.off_data_table);
|
||||
CHECK_ASSERTION(indices[i].param_max < data.size() - indices[i].data_off);
|
||||
|
||||
// Get data pointer
|
||||
const auto value_ptr = data.begin() + header.off_data_table + indices[i].data_off;
|
||||
|
||||
if (indices[i].param_fmt == format::integer && indices[i].param_max == sizeof(u32) && indices[i].param_len == sizeof(u32))
|
||||
{
|
||||
return false;
|
||||
// Integer data
|
||||
result.emplace(std::piecewise_construct,
|
||||
std::forward_as_tuple(std::move(key)),
|
||||
std::forward_as_tuple(reinterpret_cast<const le_t<u32>&>(*value_ptr)));
|
||||
}
|
||||
else if (indices[i].param_fmt == format::string || indices[i].param_fmt == format::array)
|
||||
{
|
||||
// String/array data
|
||||
std::string value;
|
||||
|
||||
if (indices[i].param_fmt == format::string)
|
||||
{
|
||||
// Find null terminator
|
||||
value.assign(value_ptr, std::find(value_ptr, value_ptr + indices[i].param_len, '\0'));
|
||||
}
|
||||
else
|
||||
{
|
||||
value.assign(value_ptr, value_ptr + indices[i].param_len);
|
||||
}
|
||||
|
||||
result.emplace(std::piecewise_construct,
|
||||
std::forward_as_tuple(std::move(key)),
|
||||
std::forward_as_tuple(indices[i].param_fmt, indices[i].param_max, std::move(value)));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Possibly unsupported format, entry ignored
|
||||
log.error("Unknown entry format (key='%s', fmt=0x%x, len=0x%x, max=0x%x)", key, indices[i].param_fmt, indices[i].param_len, indices[i].param_max);
|
||||
}
|
||||
}
|
||||
else if ((indices[i].param_fmt == psf_entry_format::string || indices[i].param_fmt == psf_entry_format::string_not_null_term)
|
||||
&& indices[i].param_max >= indices[i].param_len)
|
||||
{
|
||||
// load str data
|
||||
|
||||
const u32 size = indices[i].param_len;
|
||||
|
||||
std::unique_ptr<char[]> str(new char[size + 1]);
|
||||
|
||||
if (stream.Read(str.get(), size) != size)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
str.get()[size] = 0;
|
||||
|
||||
entries[i].vstr = str.get();
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR(LOADER, "PSFLoader::Load() failed: (i=%d) fmt=0x%x, len=0x%x, max=0x%x", i, indices[i].param_fmt, indices[i].param_len, indices[i].param_max);
|
||||
return false;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// reset data
|
||||
m_entries = std::move(entries);
|
||||
std::vector<char> save(const registry& psf)
|
||||
{
|
||||
std::vector<def_table_t> indices; indices.reserve(psf.size());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PSFLoader::Save(vfsStream& stream) const
|
||||
{
|
||||
std::vector<PSFDefTable> indices;
|
||||
|
||||
indices.resize(m_entries.size());
|
||||
|
||||
// generate header
|
||||
PSFHeader header;
|
||||
header.magic = *(u32*)"\0PSF";
|
||||
header.version = 0x101;
|
||||
header.entries_num = static_cast<u32>(m_entries.size());
|
||||
header.off_key_table = sizeof(PSFHeader) + sizeof(PSFDefTable) * header.entries_num;
|
||||
|
||||
{
|
||||
// calculate key table length and generate indices
|
||||
|
||||
u32& key_offset = header.off_data_table = 0;
|
||||
u32 data_offset = 0;
|
||||
|
||||
for (u32 i = 0; i < m_entries.size(); i++)
|
||||
{
|
||||
indices[i].key_off = key_offset;
|
||||
indices[i].data_off = data_offset;
|
||||
indices[i].param_fmt = m_entries[i].fmt;
|
||||
|
||||
key_offset += static_cast<u32>(m_entries[i].name.size()) + 1; // key size
|
||||
|
||||
switch (m_entries[i].fmt) // calculate data size
|
||||
{
|
||||
case psf_entry_format::string_not_null_term:
|
||||
{
|
||||
data_offset += (indices[i].param_len = indices[i].param_max = static_cast<u32>(m_entries[i].vstr.size()));
|
||||
break;
|
||||
}
|
||||
case psf_entry_format::string:
|
||||
{
|
||||
data_offset += (indices[i].param_len = indices[i].param_max = static_cast<u32>(m_entries[i].vstr.size()) + 1);
|
||||
break;
|
||||
}
|
||||
case psf_entry_format::integer:
|
||||
{
|
||||
data_offset += (indices[i].param_len = indices[i].param_max = 4);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
data_offset += (indices[i].param_len = indices[i].param_max = 0);
|
||||
LOG_ERROR(LOADER, "PSFLoader::Save(): (i=%d) unknown entry format (0x%x, key='%s')", i, m_entries[i].fmt, m_entries[i].name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
header.off_data_table += header.off_key_table;
|
||||
|
||||
// save header
|
||||
if (!stream.SWrite(header))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// save indices
|
||||
if (!stream.SWrite(indices[0], sizeof(PSFDefTable) * m_entries.size()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// save key table
|
||||
for (const auto& entry : m_entries)
|
||||
{
|
||||
if (!stream.SWrite(entry.name[0], entry.name.size() + 1))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// save data
|
||||
for (const auto& entry : m_entries)
|
||||
{
|
||||
switch (entry.fmt)
|
||||
{
|
||||
case psf_entry_format::string:
|
||||
{
|
||||
if (!stream.SWrite(entry.vstr[0], entry.vstr.size() + 1))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case psf_entry_format::string_not_null_term:
|
||||
{
|
||||
if (!stream.SWrite(entry.vstr[0], entry.vstr.size()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case psf_entry_format::integer:
|
||||
{
|
||||
if (!stream.SWrite(entry.vint))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void PSFLoader::Clear()
|
||||
{
|
||||
m_entries.clear();
|
||||
}
|
||||
|
||||
const PSFEntry* PSFLoader::SearchEntry(const std::string& key) const
|
||||
{
|
||||
for (auto& entry : m_entries)
|
||||
{
|
||||
if (key == entry.name)
|
||||
{
|
||||
return &entry;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PSFEntry& PSFLoader::AddEntry(const std::string& key, psf_entry_format fmt)
|
||||
{
|
||||
for (auto& entry : m_entries)
|
||||
{
|
||||
if (key == entry.name)
|
||||
{
|
||||
entry.fmt = fmt;
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
|
||||
PSFEntry new_entry = {};
|
||||
new_entry.fmt = fmt;
|
||||
new_entry.name = key;
|
||||
m_entries.push_back(new_entry);
|
||||
|
||||
return m_entries.back();
|
||||
}
|
||||
|
||||
std::string PSFLoader::GetString(const std::string& key, std::string def) const
|
||||
{
|
||||
if (const auto entry = SearchEntry(key))
|
||||
{
|
||||
if (entry->fmt == psf_entry_format::string || entry->fmt == psf_entry_format::string_not_null_term)
|
||||
{
|
||||
return entry->vstr;
|
||||
}
|
||||
}
|
||||
|
||||
return def;
|
||||
}
|
||||
|
||||
s32 PSFLoader::GetInteger(const std::string& key, s32 def) const
|
||||
{
|
||||
if (const auto entry = SearchEntry(key))
|
||||
{
|
||||
if (entry->fmt == psf_entry_format::integer)
|
||||
{
|
||||
return entry->vint;
|
||||
}
|
||||
}
|
||||
|
||||
return def;
|
||||
}
|
||||
|
||||
void PSFLoader::SetString(const std::string& key, std::string value)
|
||||
{
|
||||
AddEntry(key, psf_entry_format::string).vstr = value;
|
||||
}
|
||||
|
||||
void PSFLoader::SetInteger(const std::string& key, s32 value)
|
||||
{
|
||||
AddEntry(key, psf_entry_format::integer).vint = value;
|
||||
// Generate indices and calculate key table length
|
||||
std::size_t key_offset = 0, data_offset = 0;
|
||||
|
||||
for (const auto& entry : psf)
|
||||
{
|
||||
def_table_t index;
|
||||
index.key_off = gsl::narrow<u32>(key_offset);
|
||||
index.param_fmt = entry.second.type();
|
||||
index.param_len = entry.second.size();
|
||||
index.param_max = entry.second.max();
|
||||
index.data_off = gsl::narrow<u32>(data_offset);
|
||||
|
||||
// Update offsets:
|
||||
key_offset += gsl::narrow<u32>(entry.first.size() + 1); // key size
|
||||
data_offset += index.param_max;
|
||||
|
||||
indices.push_back(index);
|
||||
}
|
||||
|
||||
// Align next section (data) offset
|
||||
key_offset = ::align(key_offset, 4);
|
||||
|
||||
// Generate header
|
||||
header_t header;
|
||||
header.magic = *(u32*)"\0PSF";
|
||||
header.version = 0x101;
|
||||
header.off_key_table = gsl::narrow<u32>(sizeof(header_t) + sizeof(def_table_t) * psf.size());
|
||||
header.off_data_table = gsl::narrow<u32>(header.off_key_table + key_offset);
|
||||
header.entries_num = gsl::narrow<u32>(psf.size());
|
||||
|
||||
// Save header and indices
|
||||
std::vector<char> result; result.reserve(header.off_data_table + data_offset);
|
||||
|
||||
result.insert(result.end(), (char*)&header, (char*)&header + sizeof(header_t));
|
||||
result.insert(result.end(), (char*)indices.data(), (char*)indices.data() + sizeof(def_table_t) * psf.size());
|
||||
|
||||
// Save key table
|
||||
for (const auto& entry : psf)
|
||||
{
|
||||
result.insert(result.end(), entry.first.begin(), entry.first.end());
|
||||
result.push_back('\0');
|
||||
}
|
||||
|
||||
// Insert zero padding
|
||||
result.insert(result.end(), header.off_data_table - result.size(), '\0');
|
||||
|
||||
// Save data
|
||||
for (const auto& entry : psf)
|
||||
{
|
||||
const auto fmt = entry.second.type();
|
||||
const u32 max = entry.second.max();
|
||||
|
||||
if (fmt == format::integer && max == sizeof(u32))
|
||||
{
|
||||
const le_t<u32> value = entry.second.as_integer();
|
||||
result.insert(result.end(), (char*)&value, (char*)&value + sizeof(u32));
|
||||
}
|
||||
else if (fmt == format::string || fmt == format::array)
|
||||
{
|
||||
const std::string& value = entry.second.as_string();
|
||||
const std::size_t size = std::min<std::size_t>(max, value.size());
|
||||
|
||||
if (value.size() + (fmt == format::string) > max)
|
||||
{
|
||||
// TODO: check real limitations of PSF format
|
||||
log.error("Entry value shrinkage (key='%s', value='%s', size=0x%zx, max=0x%x)", entry.first, value, size, max);
|
||||
}
|
||||
|
||||
result.insert(result.end(), value.begin(), value.begin() + size);
|
||||
result.insert(result.end(), max - size, '\0'); // Write zeros up to max_size
|
||||
}
|
||||
else
|
||||
{
|
||||
throw EXCEPTION("Invalid entry format (key='%s', fmt=0x%x)", entry.first, fmt);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string get_string(const registry& psf, const std::string& key, const std::string& def)
|
||||
{
|
||||
const auto found = psf.find(key);
|
||||
|
||||
if (found == psf.end() || (found->second.type() != format::string && found->second.type() != format::array))
|
||||
{
|
||||
return def;
|
||||
}
|
||||
|
||||
return found->second.as_string();
|
||||
}
|
||||
|
||||
u32 get_integer(const registry& psf, const std::string& key, u32 def)
|
||||
{
|
||||
const auto found = psf.find(key);
|
||||
|
||||
if (found == psf.end() || found->second.type() != format::integer)
|
||||
{
|
||||
return def;
|
||||
}
|
||||
|
||||
return found->second.as_integer();
|
||||
}
|
||||
}
|
||||
|
||||
+67
-80
@@ -1,88 +1,75 @@
|
||||
#pragma once
|
||||
|
||||
struct vfsStream;
|
||||
|
||||
enum class psf_entry_format : u16
|
||||
namespace psf
|
||||
{
|
||||
string_not_null_term = 0x0004,
|
||||
string = 0x0204,
|
||||
integer = 0x0404,
|
||||
};
|
||||
|
||||
struct PSFHeader
|
||||
{
|
||||
u32 magic;
|
||||
u32 version;
|
||||
u32 off_key_table;
|
||||
u32 off_data_table;
|
||||
u32 entries_num;
|
||||
};
|
||||
|
||||
struct PSFDefTable
|
||||
{
|
||||
u16 key_off;
|
||||
psf_entry_format param_fmt;
|
||||
u32 param_len;
|
||||
u32 param_max;
|
||||
u32 data_off;
|
||||
};
|
||||
|
||||
struct PSFEntry
|
||||
{
|
||||
psf_entry_format fmt;
|
||||
std::string name;
|
||||
|
||||
s32 vint;
|
||||
std::string vstr;
|
||||
};
|
||||
|
||||
class PSFLoader
|
||||
{
|
||||
std::vector<PSFEntry> m_entries;
|
||||
|
||||
public:
|
||||
PSFLoader() = default;
|
||||
|
||||
PSFLoader(vfsStream& stream)
|
||||
enum class format : u16
|
||||
{
|
||||
Load(stream);
|
||||
array = 0x0004, // claimed to be a non-NTS string (char array)
|
||||
string = 0x0204,
|
||||
integer = 0x0404,
|
||||
};
|
||||
|
||||
class entry final
|
||||
{
|
||||
std::string m_value_string;
|
||||
u32 m_value_integer; // TODO: is it really unsigned?
|
||||
u32 m_max_size; // Entry max size (supplementary info, stored in PSF format)
|
||||
format m_type;
|
||||
|
||||
public:
|
||||
// Construct string entry, assign the value
|
||||
entry(format type, u32 max_size, const std::string& value = {})
|
||||
: m_type(type)
|
||||
, m_max_size(max_size)
|
||||
, m_value_string(value)
|
||||
{
|
||||
CHECK_ASSERTION(type == format::string || type == format::array);
|
||||
CHECK_ASSERTION(max_size);
|
||||
}
|
||||
|
||||
// Construct integer entry, assign the value
|
||||
entry(u32 value)
|
||||
: m_type(format::integer)
|
||||
, m_max_size(sizeof(u32))
|
||||
, m_value_integer(value)
|
||||
{
|
||||
}
|
||||
|
||||
const std::string& as_string() const;
|
||||
u32 as_integer() const;
|
||||
|
||||
entry& operator =(const std::string& value);
|
||||
entry& operator =(u32 value);
|
||||
|
||||
format type() const { return m_type; }
|
||||
u32 max() const { return m_max_size; }
|
||||
u32 size() const;
|
||||
};
|
||||
|
||||
// Define PSF registry as a sorted map of entries:
|
||||
using registry = std::map<std::string, entry>;
|
||||
|
||||
// Load PSF registry from binary data
|
||||
registry load(const std::vector<char>&);
|
||||
|
||||
// Convert PSF registry to binary format
|
||||
std::vector<char> save(const registry&);
|
||||
|
||||
// Get string value or default value
|
||||
std::string get_string(const registry& psf, const std::string& key, const std::string& def = {});
|
||||
|
||||
// Get integer value or default value
|
||||
u32 get_integer(const registry& psf, const std::string& key, u32 def = 0);
|
||||
|
||||
// Make string entry
|
||||
inline entry string(u32 max_size, const std::string& value)
|
||||
{
|
||||
return{ format::string, max_size, value };
|
||||
}
|
||||
|
||||
virtual ~PSFLoader() = default;
|
||||
|
||||
bool Load(vfsStream& stream);
|
||||
bool Save(vfsStream& stream) const;
|
||||
void Clear();
|
||||
|
||||
explicit operator bool() const
|
||||
// Make array entry
|
||||
inline entry array(u32 max_size, const std::string& value)
|
||||
{
|
||||
return !m_entries.empty();
|
||||
return{ format::array, max_size, value };
|
||||
}
|
||||
|
||||
const PSFEntry* SearchEntry(const std::string& key) const;
|
||||
PSFEntry& AddEntry(const std::string& key, psf_entry_format format);
|
||||
std::string GetString(const std::string& key, std::string def = "") const;
|
||||
s32 GetInteger(const std::string& key, s32 def = 0) const;
|
||||
void SetString(const std::string& key, std::string value);
|
||||
void SetInteger(const std::string& key, s32 value);
|
||||
|
||||
std::vector<PSFEntry>& entries()
|
||||
{
|
||||
return m_entries;
|
||||
}
|
||||
|
||||
const std::vector<PSFEntry>& entries() const
|
||||
{
|
||||
return m_entries;
|
||||
}
|
||||
|
||||
std::vector<PSFEntry>::iterator begin()
|
||||
{
|
||||
return m_entries.begin();
|
||||
}
|
||||
|
||||
std::vector<PSFEntry>::iterator end()
|
||||
{
|
||||
return m_entries.end();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
+34
-34
@@ -62,9 +62,9 @@ enum class rsx_aspect_ratio
|
||||
enum class rsx_frame_limit
|
||||
{
|
||||
Off,
|
||||
_30,
|
||||
_50,
|
||||
_59_94,
|
||||
_30,
|
||||
_60,
|
||||
Auto
|
||||
};
|
||||
@@ -155,9 +155,9 @@ namespace convert
|
||||
switch (value)
|
||||
{
|
||||
case rsx_frame_limit::Off: return "Off";
|
||||
case rsx_frame_limit::_30: return "30";
|
||||
case rsx_frame_limit::_50: return "50";
|
||||
case rsx_frame_limit::_59_94: return "59.94";
|
||||
case rsx_frame_limit::_30: return "30";
|
||||
case rsx_frame_limit::_60: return "60";
|
||||
case rsx_frame_limit::Auto: return "Auto";
|
||||
}
|
||||
@@ -174,15 +174,15 @@ namespace convert
|
||||
if (value == "Off")
|
||||
return rsx_frame_limit::Off;
|
||||
|
||||
if (value == "30")
|
||||
return rsx_frame_limit::_30;
|
||||
|
||||
if (value == "50")
|
||||
return rsx_frame_limit::_50;
|
||||
|
||||
if (value == "59.94")
|
||||
return rsx_frame_limit::_59_94;
|
||||
|
||||
if (value == "30")
|
||||
return rsx_frame_limit::_30;
|
||||
|
||||
if (value == "60")
|
||||
return rsx_frame_limit::_60;
|
||||
|
||||
@@ -836,8 +836,8 @@ namespace rpcs3
|
||||
|
||||
} llvm{ this };
|
||||
|
||||
entry<ppu_decoder_type> ppu_decoder { this, "PPU Decoder", ppu_decoder_type::interpreter };
|
||||
entry<spu_decoder_type> spu_decoder { this, "SPU Decoder", spu_decoder_type::interpreter_precise };
|
||||
entry<ppu_decoder_type> ppu_decoder { this, "PPU decoder", ppu_decoder_type::interpreter };
|
||||
entry<spu_decoder_type> spu_decoder { this, "SPU decoder", spu_decoder_type::interpreter_precise };
|
||||
entry<bool> hook_st_func { this, "Hook static functions", false };
|
||||
entry<bool> load_liblv2 { this, "Load liblv2.sprx", false };
|
||||
|
||||
@@ -849,30 +849,30 @@ namespace rpcs3
|
||||
{
|
||||
opengl_group(group *grp) : group{ grp, "opengl" } {}
|
||||
|
||||
entry<bool> write_color_buffers { this, "Write Color Buffers", true };
|
||||
entry<bool> write_depth_buffer { this, "Write Depth Buffer", true };
|
||||
entry<bool> read_color_buffers { this, "Read Color Buffers", true };
|
||||
entry<bool> read_depth_buffer { this, "Read Depth Buffer", true };
|
||||
entry<bool> write_color_buffers { this, "Write color buffers", true };
|
||||
entry<bool> write_depth_buffer { this, "Write depth buffer", true };
|
||||
entry<bool> read_color_buffers { this, "Read color buffers", true };
|
||||
entry<bool> read_depth_buffer { this, "Read depth buffer", true };
|
||||
} opengl{ this };
|
||||
|
||||
struct d3d12_group : protected group
|
||||
{
|
||||
d3d12_group(group *grp) : group{ grp, "d3d12" } {}
|
||||
|
||||
entry<u32> adaptater { this, "D3D Adaptater", 1 };
|
||||
entry<bool> debug_output { this, "Debug Output", false };
|
||||
entry<u32> adaptater { this, "D3D adapter", 0 };
|
||||
entry<bool> debug_output { this, "Debug output", false };
|
||||
entry<bool> overlay { this, "Debug overlay", false };
|
||||
} d3d12{ this };
|
||||
|
||||
rsx_group(config_context_t *cfg) : group{ cfg, "rsx" } {}
|
||||
|
||||
entry<rsx_renderer_type> renderer { this, "Renderer", rsx_renderer_type::OpenGL };
|
||||
entry<rsx_renderer_type> renderer { this, "Rendering API", rsx_renderer_type::OpenGL };
|
||||
entry<rsx_resolution> resolution { this, "Resolution", rsx_resolution::_720x480 };
|
||||
entry<rsx_aspect_ratio> aspect_ratio{ this, "Aspect ratio", rsx_aspect_ratio::_16x9 };
|
||||
entry<rsx_frame_limit> frame_limit { this, "Frame limit", rsx_frame_limit::Off };
|
||||
entry<bool> log_programs { this, "Log shader programs", false };
|
||||
entry<bool> vsync { this, "VSync", false };
|
||||
entry<bool> _3dtv { this, "3D Monitor", false };
|
||||
entry<bool> _3dtv { this, "3D monitor", false };
|
||||
|
||||
} rsx{ this };
|
||||
|
||||
@@ -880,33 +880,33 @@ namespace rpcs3
|
||||
{
|
||||
audio_group(config_context_t *cfg) : group{ cfg, "audio" } {}
|
||||
|
||||
entry<audio_output_type> out{ this, "Audio Out", audio_output_type::OpenAL };
|
||||
entry<audio_output_type> out{ this, "Audio out", audio_output_type::OpenAL };
|
||||
entry<bool> dump_to_file { this, "Dump to file", false };
|
||||
entry<bool> convert_to_u16 { this, "Convert to 16 bit", false };
|
||||
entry<bool> convert_to_u16 { this, "Convert to 16-bit", false };
|
||||
} audio{ this };
|
||||
|
||||
struct io_group : protected group
|
||||
{
|
||||
io_group(config_context_t *cfg) : group{ cfg, "io" } {}
|
||||
|
||||
entry<io_camera_state> camera { this, "Camera", io_camera_state::connected };
|
||||
entry<io_camera_type> camera_type { this, "Camera type", io_camera_type::play_station_eye };
|
||||
entry<io_handler_mode> pad_handler_mode { this, "Pad Handler", io_handler_mode::windows };
|
||||
entry<io_handler_mode> keyboard_handler_mode{ this, "Keyboard Handler", io_handler_mode::null };
|
||||
entry<io_handler_mode> mouse_handler_mode { this, "Mouse Handler", io_handler_mode::null };
|
||||
entry<io_camera_state> camera { this, "Camera", io_camera_state::connected };
|
||||
entry<io_camera_type> camera_type { this, "Camera type", io_camera_type::play_station_eye };
|
||||
entry<io_handler_mode> pad_handler_mode { this, "Controller handler", io_handler_mode::windows };
|
||||
entry<io_handler_mode> keyboard_handler_mode{ this, "Keyboard handler", io_handler_mode::null };
|
||||
entry<io_handler_mode> mouse_handler_mode { this, "Mouse handler", io_handler_mode::null };
|
||||
|
||||
struct pad_group : protected group
|
||||
{
|
||||
pad_group(group *grp) : group{ grp, "pad" } {}
|
||||
|
||||
entry<int> left_stick_left { this, "Left Analog Stick Left", 314 };
|
||||
entry<int> left_stick_down { this, "Left Analog Stick Down", 317 };
|
||||
entry<int> left_stick_right { this, "Left Analog Stick Right", 316 };
|
||||
entry<int> left_stick_up { this, "Left Analog Stick Up", 315 };
|
||||
entry<int> right_stick_left { this, "Right Analog Stick Left", 313 };
|
||||
entry<int> right_stick_down { this, "Right Analog Stick Down", 367 };
|
||||
entry<int> right_stick_right{ this, "Right Analog Stick Right", 312 };
|
||||
entry<int> right_stick_up { this, "Right Analog Stick Up", 366 };
|
||||
entry<int> left_stick_left { this, "Left analog stick Left", 314 };
|
||||
entry<int> left_stick_down { this, "Left analog stick Down", 317 };
|
||||
entry<int> left_stick_right { this, "Left analog stick Right", 316 };
|
||||
entry<int> left_stick_up { this, "Left analog stick Up", 315 };
|
||||
entry<int> right_stick_left { this, "Right analog stick Left", 313 };
|
||||
entry<int> right_stick_down { this, "Right analog stick Down", 367 };
|
||||
entry<int> right_stick_right{ this, "Right analog stick Right", 312 };
|
||||
entry<int> right_stick_up { this, "Right analog stick Up", 366 };
|
||||
entry<int> start { this, "Start", 13 };
|
||||
entry<int> select { this, "Select", 32 };
|
||||
entry<int> square { this, "Square", static_cast<int>('J') };
|
||||
@@ -935,8 +935,8 @@ namespace rpcs3
|
||||
{
|
||||
log_group(group *grp) : group{ grp, "log" } {}
|
||||
|
||||
entry<_log::level> level { this, "Log Level", _log::level::success };
|
||||
entry<bool> rsx_logging { this, "RSX Logging", false };
|
||||
entry<_log::level> level { this, "Log level", _log::level::success };
|
||||
entry<bool> rsx_logging { this, "RSX logging", false };
|
||||
} log{ this };
|
||||
|
||||
struct net_group : protected group
|
||||
@@ -951,8 +951,8 @@ namespace rpcs3
|
||||
{
|
||||
debug_group(group *grp) : group{ grp, "debug" } {}
|
||||
|
||||
entry<bool> auto_pause_syscall { this, "Auto Pause at System Call", false };
|
||||
entry<bool> auto_pause_func_call { this, "Auto Pause at Function Call", false };
|
||||
entry<bool> auto_pause_syscall { this, "Automatically pause at system call", false };
|
||||
entry<bool> auto_pause_func_call { this, "Automatically pause at function call", false };
|
||||
} debug{ this };
|
||||
|
||||
entry<bool> exit_on_stop { this, "Exit RPCS3 when process finishes", false };
|
||||
|
||||
@@ -87,6 +87,7 @@
|
||||
<ClCompile Include="Emu\RSX\Common\FragmentProgramDecompiler.cpp" />
|
||||
<ClCompile Include="Emu\RSX\Common\ProgramStateCache.cpp" />
|
||||
<ClCompile Include="Emu\RSX\Common\ShaderParam.cpp" />
|
||||
<ClCompile Include="Emu\RSX\Common\surface_store.cpp" />
|
||||
<ClCompile Include="Emu\RSX\Common\TextureUtils.cpp" />
|
||||
<ClCompile Include="Emu\RSX\Common\VertexProgramDecompiler.cpp" />
|
||||
<ClCompile Include="Emu\RSX\GCM.cpp" />
|
||||
@@ -516,6 +517,7 @@
|
||||
<ClInclude Include="Emu\RSX\Common\FragmentProgramDecompiler.h" />
|
||||
<ClInclude Include="Emu\RSX\Common\ProgramStateCache.h" />
|
||||
<ClInclude Include="Emu\RSX\Common\ShaderParam.h" />
|
||||
<ClInclude Include="Emu\RSX\Common\surface_store.h" />
|
||||
<ClInclude Include="Emu\RSX\Common\TextureUtils.h" />
|
||||
<ClInclude Include="Emu\RSX\Common\VertexProgramDecompiler.h" />
|
||||
<ClInclude Include="Emu\RSX\GCM.h" />
|
||||
|
||||
@@ -936,6 +936,9 @@
|
||||
<ClCompile Include="Emu\RSX\Common\ProgramStateCache.cpp">
|
||||
<Filter>Emu\GPU\RSX\Common</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Emu\RSX\Common\surface_store.cpp">
|
||||
<Filter>Emu\GPU\RSX\Common</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Crypto\aes.h">
|
||||
@@ -1788,5 +1791,8 @@
|
||||
<ClInclude Include="..\stblib\stb_image.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Emu\RSX\Common\surface_store.h">
|
||||
<Filter>Emu\GPU\RSX\Common</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
+3
-3
@@ -3,7 +3,7 @@
|
||||
<ImportGroup Label="PropertySheets" />
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup>
|
||||
<IncludePath>.\;..\;..\asmjit\src\asmjit;..\wxWidgets\include\msvc;..\wxWidgets\include;..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\Include;$(VC_IncludePath);$(WindowsSDK_IncludePath);..\llvm\include;..\llvm_build\include;$(UniversalCRT_IncludePath);..\minidx12\Include;..\glm;..\GSL\include</IncludePath>
|
||||
<IncludePath>.\;..\;..\asmjit\src\asmjit;..\wxWidgets\include\msvc;..\wxWidgets\include;..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\Include;$(VC_IncludePath);$(WindowsSDK_IncludePath);..\llvm\include;..\llvm_build\include;$(UniversalCRT_IncludePath);..\minidx12\Include;..\glm;..\GSL\include;..\libpng</IncludePath>
|
||||
<OutDir>$(SolutionDir)lib\$(Configuration)-$(Platform)\</OutDir>
|
||||
<LibraryPath>$(SolutionDir)lib\$(Configuration)-$(Platform)\;$(UniversalCRT_LibraryPath_x64);$(LibraryPath)</LibraryPath>
|
||||
<IntDir>$(SolutionDir)tmp\$(ProjectName)-$(Configuration)-$(Platform)\</IntDir>
|
||||
@@ -25,9 +25,9 @@
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>odbc32.lib;odbccp32.lib;comctl32.lib;ws2_32.lib;shlwapi.lib;winmm.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;rpcrt4.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>odbc32.lib;odbccp32.lib;comctl32.lib;ws2_32.lib;shlwapi.lib;winmm.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;rpcrt4.lib;libpng.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<DataExecutionPrevention>true</DataExecutionPrevention>
|
||||
<AdditionalLibraryDirectories>..\wxWidgets\lib\vc_x64_lib;..\ffmpeg\Windows\x86_64\lib</AdditionalLibraryDirectories>
|
||||
<AdditionalLibraryDirectories>..\wxWidgets\lib\vc_x64_lib;..\ffmpeg\Windows\x86_64\lib;..\lib\</AdditionalLibraryDirectories>
|
||||
<BaseAddress>0x10000</BaseAddress>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
</Link>
|
||||
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
* zlib.props - location of zlib source
|
||||
*
|
||||
* libpng version 1.6.20 - December 3, 2015
|
||||
*
|
||||
* Copyright (c) 1998-2011 Glenn Randers-Pehrson
|
||||
*
|
||||
* This code is released under the libpng license.
|
||||
* For conditions of distribution and use, see the disclaimer
|
||||
* and license in png.h
|
||||
|
||||
* You must edit this file to record the location of the zlib
|
||||
* source code.
|
||||
-->
|
||||
|
||||
<Project ToolsVersion="4.0"
|
||||
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup Label="Globals">
|
||||
<!-- Place the name of the directory containing the source of zlib used for
|
||||
debugging in this property.
|
||||
|
||||
The directory need only contain the '.c' and '.h' files from the
|
||||
source.
|
||||
|
||||
If you use a relative directory name (as below) then it must be
|
||||
relative to the project directories; these are one level deeper than
|
||||
the directories containing this file.
|
||||
|
||||
If the version of zlib you use does not match that used when the
|
||||
distribution was built you will get warnings from pngtest that the zlib
|
||||
versions do not match. The zlib version used in this build is recorded
|
||||
below:
|
||||
-->
|
||||
<ZLibSrcDir>..\..\..\..\wxWidgets\src\zlib\</ZLibSrcDir>
|
||||
|
||||
<!-- The following line allows compilation for an ARM target with Visual
|
||||
Studio 2012. Notice that this is not supported by the Visual Studio
|
||||
2012 IDE and that the programs that result cannot be run unless they
|
||||
signed by Microsoft. This is therefore untested; only Microsoft can
|
||||
test it:
|
||||
-->
|
||||
<WindowsSDKDesktopARMSupport>true</WindowsSDKDesktopARMSupport>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
Reference in New Issue
Block a user